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

WIP: External code snippets and example code #81

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions codeblocks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
83 changes: 83 additions & 0 deletions codeblocks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const visit = require('unist-util-visit');
const { join, dirname } = require('path');
const CACHEDIR = join(__dirname, '../.cache');
const { mkdir } = require('fs');
const fetch = require('node-fetch')

const plugin = (options) => {
const transformer = async (ast, vfile) => {
//DEBUG:
//if (vfile.path.includes('test.md')) console.log(ast)

const cblocks = []
const assets = []

// Collect all (relevant) codeblocks
visit(ast, 'code', async (node) => {
// In this extension we repurpose the language hint for a source URL
// Code blocks that need their URL cached & replaced with the correct imports:
if (node.lang?.startsWith('http://') || node.lang?.startsWith('https://')) {
cblocks.push(node)
}
});

//DEBUG:
//if (cblocks.length) console.log(cblocks)

// We run the changes outside of the visitor because the visitor does not support callbacks
for (const node of cblocks) {
const url = node.lang;
const lang = await detectLang(url);
const file = await cachedFile(url);
node.lang = lang
assets.push(file.path)
const assetId = assets.length-1

// TODO: decide whether to use asset imports & external files or embedded content
node.value = `/* ${url} {__externalCodeSnippet${assetId}} */\n` + file.contents;
}

//DEBUG:
//if (cblocks.length) console.log(cblocks, assets)
};
return transformer;
};

module.exports = plugin;


async function detectLang(url) {
//TODO:
return 'rust'
}

async function cachedFile(url) {
// Convert the URL into a cache path
const path = cachePath(url);
if (!path) {
return `/* ERROR: could not cache file: ${url} */`
}
// TODO: maybe we want to have a whitelist for allowed paths?
// E.g. limit to https://raw.githubusercontent.com/suborbital/**

// <check if file is already cached at p>

// TODO: handle request errors
const contents = await fetch(url).then(r => r.text());

// <ensure recursively mkdir(dirname(p))
// <cache file contents at p>

// Return both path and contents
return { path, contents }
}

function cachePath(url) {
const p = (/https?:\/\/(.*)/.exec(url) ?? [])[1];
if (!p) {
console.error('Cache path invalid!');
return void 0;
}

return join(CACHEDIR, p);
}
154 changes: 154 additions & 0 deletions codeblocks/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions codeblocks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "codeblocks",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"node-fetch": "^2.6.7",
"unist-util-visit": "^2.0.1"
}
}
4 changes: 4 additions & 0 deletions website/code/rwasm-testdata/fetch/.runnable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: fetch
namespace: default
lang: rust
apiVersion: 0.2.5
60 changes: 60 additions & 0 deletions website/code/rwasm-testdata/fetch/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions website/code/rwasm-testdata/fetch/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "fetch"
version = "0.1.0"
authors = ["Suborbital Runnable <info@suborbital.dev>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
suborbital = { path = "../../../api/rust/core" }
Binary file added website/code/rwasm-testdata/fetch/fetch.wasm
Binary file not shown.
42 changes: 42 additions & 0 deletions website/code/rwasm-testdata/fetch/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use suborbital::runnable::*;
use suborbital::http;
use suborbital::util;
use suborbital::log;
use std::collections::BTreeMap;

struct Fetch{}

impl Runnable for Fetch {
fn run(&self, input: Vec<u8>) -> Result<Vec<u8>, RunErr> {
let url = util::to_string(input);

let _ = match http::get(url.as_str(), None) {
Ok(res) => res,
Err(e) => return Err(RunErr::new(1, e.message.as_str()))
};

// test sending a POST request with headers and a body
let mut headers = BTreeMap::new();
headers.insert("Content-Type", "application/json");
headers.insert("X-ATMO-TEST", "testvalgoeshere");

let body = String::from("{\"message\": \"testing the echo!\"}").as_bytes().to_vec();

match http::post("https://postman-echo.com/post", Some(body), Some(headers)) {
Ok(res) => {
log::info(util::to_string(res.clone()).as_str());
Ok(res)
},
Err(e) => Err(RunErr::new(1, e.message.as_str()))
}
}
}


// initialize the runner, do not edit below //
static RUNNABLE: &Fetch = &Fetch{};

Comment on lines +9 to +38
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks very exciting!

I would love to try and use it, but am running into bumps. Would it be helpful to have a handler and curl request example, too?

Or maybe make this a part of a greater sample project?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah sorry, I just used this as an example, haven't tried if it actually worked -- just pulled it out of the rwasm-testdata 🙈

#[no_mangle]
pub extern fn _start() {
use_runnable(RUNNABLE);
}
8 changes: 8 additions & 0 deletions website/docs/atmo/runnable-api/http-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,11 @@ public func HttpDelete(url: String) -> String
```

</MultiLanguageCodeBlock>


## Example Runnable

import CodeBlock from '@theme/CodeBlock';
import exampleCodeRustFetch from '@code/rwasm-testdata/fetch/src/lib.rs';

<CodeBlock className="language-rust">{exampleCodeRustFetch}</CodeBlock>
Loading