Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document API & architecture #143

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ updates to any changes as you are typing and the scrolling is smoothly
synchronized!

See below for a list of existing editor plugins. In case your favorite editor is
not yet supported, use these as an example to write your own and add it to the
list!
not yet supported, use these as an example to write your own or check out the
[API documentation](docs/api.md) and add it to the list!

#### Existing integration

Expand Down
72 changes: 72 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Vivify's API

In addition to the command line interface `viv`, Vivify has HTTP endpoints that
can be used to integrate it into other applications, such as making editor
plugins for live previews.

## Path encoding

Vivify's endpoints are often accessed with the pattern `/<endpoint>/<path>`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be fair to say they are always accessed with that pattern? I would consider just dropping the word often.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have GET /health and DELETE /viewer at the root of the endpoints with no paths.

We could instead say something like

Current wording

Vivify's endpoints are often accessed with the pattern /<endpoint>/<path> where path is a percent-encoded path in the file system.

Suggestion

When accessing an endpoint corresponding to a path in the file system, use /<endpoint>/<path> where <path> is percent-encoded.

Is that better? ^^

where path is a
[percent-encoded](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding)
path in the file system. For paths that follow UNIX naming conventions, this
means that endpoints can be accessed directly at the literal paths. For example,
accessing `<endpoint>` for a file at `/Users/me/my-file.md` can be done through
the URL

```txt
/<endpoint>/Users/me/my-file.md
```

For paths that have special characters such as spaces, we have to rely on the
[percent-encoding](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding).
E.g. to access `<endpoint>` for a file at `Users/me/my file.md`, it will be the
following.

```txt
/<endpoint>/Users/me/my%20file.md
```

## Endpoints

Vivify has two routes of endpoints, `/health`, and `/viewer`.

### `/health`

This endpoint is used for checking the status of Vivify Server and its clients
(connected viewers). Sending a `GET` request directly to `/health` will reply
with status 200 if Vivify Server is running. Sending a `GET` request to
`/health/<path>` (as defined in [Path encoding](#path-encoding)) will reply with
status 200 if there are clients connected at the given path, or with 404 if
there aren't.

### `/viewer`

This endpoint is used to manipulate connected clients.

Sending a `POST` to `/viewer/<path>` (as defined in [Path
encoding](#path-encoding)) will always reply with the following response.

```typescript
{
"clients": number // number of clients connected at <path>
}
```

The request can include a body with the following optional fields.

```typescript
{
"content": string, // Live update the entire file's content to the given
// value.
"cursor": number, // For markdown files, scroll all viewers to the content
// corresponding to the given line in the source file.
"reload": boolean // Live update the viewer based on the current content
// on disk. Note that this overrides "content".
}
```

Sending a `DELETE` request to `/viewer` will fully reload all connected clients
at any paths and clear all cached updated live content. Sending a `DELETE`
request to `/viewer/<path>` (as defined in [Path encoding](#path-encoding)) will
do the same for all clients at the given path.
54 changes: 54 additions & 0 deletions docs/architecture.md
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a rough draft, probably makes more sense if I edit it offline using my local text editor and this awesome markdown viewer I found called Vivify 🤣

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sounds good! That's the idea that you write the whole thing haha, the stuff I wrote into the document is only for you, not for main :D

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rgr. Do you plan to merge api.md and leave architecture.md out? I've already pulled it down so I can keep working on it.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I don't mind. I was thinking to leave this PR laying around until you are done with the architecture document, I don't think we are in a big rush here. Or what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me, I am... thinking about putting in a job app this week, and then its my weekend for kid wrangling duties, so I might not get to it soon is all.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Architecture overview

intro text

## Scope of this repository

This repo includes just main Vivify which aims to be very configurable and
easily integrable. Everything else (e.g. vivify.vim) are their own projects with
their own repos

## Executables

we have two executables: `viv` and `vivify-server`:

- `viv` is just a small wrapper that
1. runs Vivify Server
2. forwards everything Vivify Server prints to `stdout` to its own `stdout`
until the server prints `STARTUP COMPLETE`
3. disowns the server process so it keeps running in the background while
`viv` can terminate
- `vivify-server` is the actual Node.js app that does almost everything and is
described in the rest of this doc

## Vivify Server overview

- (focus on `src/app.ts`) When `vivify-server` is called, there are two
scenarios which we distinguish through the [`/health` endpoint](docs/api.md):
1. There is already another instance of Vivify Server running: We have to
reuse that instance and have it open the requested viewer.
2. There is no other instance running: We have to start the server and
then handle the requests ourselves.
- Vivify Server is
1. an [Express](http://expressjs.com) server that serves the
[API](docs/api.md) and the viewers
2. (focus on `src/sockets.ts`) a WebSocket server that keeps 1 socket
connection with each client (viewer browser tab) to
1. be able to manipulate clients, e.g. for editor integration
2. know when there are no clients left so we can shut down Vivify Server
- rendering files happens in the `src/parser` directory
- for Markdown we use [markdown-it](https://www.npmjs.com/package/markdown-it)
and most Markdown features can be handled with plugins from there
- Notebook rendering is implemented from scratch but by heavily relying on the
existing ability render Markdown

## Build infrastructure overview

- we use [Node SEA](https://nodejs.org/api/single-executable-applications.html)
which is still in beta to compile Vivify Server into a single executable
without needing a Node dependency
- this is why we can't simply use native Express static router but had to come
up with a custom solution in `src/routes/static.ts`:
- at development time, we just serve whatever is in the `static/` directory
- at production time we access all contents of the `static/` directory through
an archive that is included as an asset in the SEA