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

feat: website #3

Merged
merged 2 commits into from
Feb 27, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
39 changes: 39 additions & 0 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Deploy Website to GitHub Pages

on:
push:
branches: [main]

jobs:
deploy:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
defaults:
run:
working-directory: website
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16.x
cache: npm

- name: Build website
run: |
npm ci
npm run build

# Popular action to deploy to GitHub Pages:
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Build output to publish to the `gh-pages` branch:
publish_dir: ./build
# Assign commit authorship to the official GH-Actions bot for deploys to `gh-pages` branch:
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
# The GH actions bot is used by default if you didn't specify the two fields.
# You can swap them out with your own user credentials.
user_name: github-actions[bot]
user_email: 41898282+github-actions[bot]@users.noreply.github.com
20 changes: 20 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
41 changes: 41 additions & 0 deletions website/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Website

This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.

### Installation

```
$ yarn
```

### Local Development

```
$ yarn start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

### Build

```
$ yarn build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

### Deployment

Using SSH:

```
$ USE_SSH=true yarn deploy
```

Not using SSH:

```
$ GIT_USER=<Your GitHub username> yarn deploy
```

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
3 changes: 3 additions & 0 deletions website/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
5 changes: 5 additions & 0 deletions website/docs/api-versions/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "API Versions",
"position": 2
}

152 changes: 152 additions & 0 deletions website/docs/api-versions/gRPC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
id: gRPC
title: gRPC (reccomended)
sidebar_position: 0
---

v3 of the Export API introduces a gRPC API. One of the major upsides of using the gRPC protocol is a stream of progress updates and finally streaming the file back to the client.

The `@fyko/export-api` package includes a typed JavaScript client and will be referenced in this part of the documentation.

## Protobuf Definition

:::tip Server Reflection
The gRPC service has [server reflection](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md), allowing you to test the API in Postman.
:::

```protobuf
service Exporter {
rpc CreateExport (CreateExportRequest) returns (stream CreateExportResponse);
}

enum ExportFormat {
PlainText = 0;
HtmlDark = 1;
HtmlLight = 2;
CSV = 3;
JSON = 4;
}

message CreateExportRequest {
string token = 1;
string channel_id = 2;
ExportFormat export_format = 3;
string date_format = 4;
string after = 5;
string before = 6;
}

message CreateExportResponse {
oneof ResponseType {
double progress = 1;
ExportComplete data = 2;
}
}

message ExportComplete {
int32 message_count = 1;
bytes data = 2;
}
```

## `Exporter/CreateExport`

> `rpc CreateExport (CreateExportRequest) returns (stream CreateExportResponse);`

### Export Formats Enum

| **Type** | **ID** | **Description** | **File Extension** |
| --------- | ------ | --------------------------------------- | ------------------ |
| PlainText | 0 | Export to a plaintext file | txt |
| HtmlDark | 1 | Export to an HTML file in dark mode | html |
| HtmlLight | 2 | Export to an HTML file in light mode | html |
| CSV | 3 | Export to a comma separated values file | csv |
| JSON | 4 | Export to a JSON file | json |

### CreateExportRequest

| **Field** | **Type** | **Description** |
| ------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| token | string | The bot token for performing requests |
| channel_id | string | The id of the channel to export |
| export_format | ?[ExportFormat](#export-formats-enum) | The format to export the channel as, defaults to `PlainText` |
| date_format | ?string | The [date format](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings) for dates in exported files, defaults to `dd-MMM-yy hh:mm tt` |
| after | ?string | Only include messages sent after this date |
| before | ?string | Only include messages sent before this date |

### CreateExportResponse

| **Field** | **Type** | **Description** |
| --------- | ---------------------------------- | ------------------------------------------------- |
| progress | int64 | A decimal representing the progress of the export |
| data | ?[ExportComplete](#exportcomplete) | The file data once `progress` equals `1` |

### ExportComplete

| **Field** | **Type** | **Description** |
| ------------- | -------- | -------------------------------- |
| message_count | int | The number of messages exported |
| data | byte[] | The exported file in 32kb chunks |

### Example

```ts
import { credentials } from "@grpc/grpc-js";
import { ExporterClient } from "@fyko/export-api/client";
import {
CreateExportRequest,
CreateExportResponse,
ExportFormat,
} from "@fyko/export-api/types";
import { writeFile } from "fs/promises";

// creates a new gRPC client
const client = new ExporterClient(
`localhost:${process.env.PORT}`,
credentials.createInsecure()
);

void (async () => {
// new CreateExport Request
const request = new CreateExportRequest();
// set required options
request.setChannelId(process.env.DISCORD_CHANNEL!);
request.setToken(process.env.DISCORD_TOKEN!);
// set optional options
request.setExportFormat(ExportFormat.HTMLDARK);

//
return new Promise(async (res, rej) => {
// "POST" the request
const stream = client.createExport(request);

const chunks: (string | Uint8Array)[] = [];
let progress = 0;
stream.on("data", (response: CreateExportResponse) => {
// if `response.progress` is present
const p = response.getProgress();
if (p && p > progress) {
progress = p;
console.log((p * 100).toFixed() + "%");
}

// if finally sending the file itself, push to chunk array
const data = response.getData();
const inner = data?.getData();
if (inner) {
console.log(`Inner exists!`);
chunks.push(inner);
}
});

// once the server closes the stream,
// we can finally write the file
stream.on("end", async () => {
await writeFile("./foo.html", chunks);
return res(void 0);
});

stream.on("error", rej);
});
})();
```
67 changes: 67 additions & 0 deletions website/docs/api-versions/v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
id: v1
title: v1
sidebar_position: 0
---

:::danger API Deprecated
This API version is deprecated, it's advised you use either [v2](v2.md) or [gRPC](gRPC.md).
:::

## `POST` `/v1/export`
__JSON Body__

| **Field** | **Type** | **Description** |
|-----------|----------|---------------------------------------|
| token | string | The bot token for performing requests |
| channelId | string | The id of the channel to export |

__Response Codes__

| **Status** | **Description** |
|------------|----------------------------------------------|
| 200 | Success - exported channel sent as text/html |
| 401 | Unauthorized - bad Discord bot token |
| 409 | Conflict - unknown channel |

### Examples
#### Typescript:
```ts
import fetch from 'node-fetch';

async function exportChannel(channelId: string, token: string): Promise<Buffer> {
const response = await fetch('http://exportapi:80/v1/export', {
method: 'POST',
body: JSON.stringify({ channelId, token }),
headers: {
'Content-Type': 'application/json'
}
});
if (response.ok) {
return response.buffer();
}
throw Error('Channel export failed!');
}
```
#### Rust
```rust
// reqwest = { version = "0.10", features = ["json"] }
use reqwest::Client;
use std::collections::HashMap;
use std::io::copy;
use std::fs::File;

async fn export_channel(channelId: &str, token: &str) -> Result<File, reqwest::Error> {
let client = Client::new();
let mut map = HashMap::new();
map.insert("channelId", "channel id");
map.insert("token", "discord token");

let file = client.post("http://exportapi:80/v1/export").json(&map).await?.text().await?;

let dest = File::create("myexport.html")?;
copy(&mut file.as_bytes(), &mut dest)?;

Ok(dest)
}
```
Loading