Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

Commit

Permalink
feat(xkcd)!: add simple UI to XKCD actor
Browse files Browse the repository at this point in the history
Signed-off-by: Brooks Townsend <brooks@cosmonic.com>
  • Loading branch information
brooksmtownsend committed Sep 13, 2023
1 parent 4d6a78c commit a1c4db8
Show file tree
Hide file tree
Showing 43 changed files with 34,112 additions and 76 deletions.
2 changes: 1 addition & 1 deletion actor/xkcd/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
target
build
/build
76 changes: 75 additions & 1 deletion actor/xkcd/Cargo.lock

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

10 changes: 6 additions & 4 deletions actor/xkcd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "xkcd"
version = "0.1.7"
authors = [ "wasmcloud Team" ]
version = "0.2.0"
authors = ["wasmcloud Team"]
edition = "2021"

[lib]
Expand All @@ -11,12 +11,14 @@ crate-type = ["cdylib", "rlib"]
async-trait = "0.1"
futures = "0.3"
serde_bytes = "0.11"
serde_json ="1.0"
serde = {version = "1.0", features = ["derive"]}
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
wasmbus-rpc = "0.13"
wasmcloud-interface-httpserver = "0.10"
wasmcloud-interface-httpclient = "0.9"
wasmcloud-interface-numbergen = "0.9"
rust-embed = "8.0.0"
mime_guess = "2.0.4"

[profile.release]
# Optimize for small code size
Expand Down
5 changes: 5 additions & 0 deletions actor/xkcd/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# examples/actor/xkcd

.PHONY: build
PROJECT = xkcd
VERSION = $(shell cargo metadata --no-deps --format-version 1 | jq -r '.packages[] .version' | head -1)
REVISION = 2
Expand All @@ -20,6 +21,10 @@ ACTOR_ID = $(shell make actor_id)
HTTPSERVER_PROVIDER_ID = VAG3QITQQ2ODAOWB5TTQSDJ53XK3SHBEIFNK4AYJ5RKAX2UNSCAPHA5M
HTTPCLIENT_PROVIDER_ID = VCCVLH4XWGI3SGARFNYKYT2A32SUYA2KVAIV2U2Q34DQA7WWJPFRKIKM

build:
cd ui && npm run build
wash build


link:
# link to httpserver and httpclient
Expand Down
45 changes: 8 additions & 37 deletions actor/xkcd/README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,20 @@
# Xkcd comic generator

This example actor demonstrates three capability providers:
- wasmcloud:httpserver for responding to http requests
- wasmcloud:httpclient for fetching http resources from the internet

- wasmcloud:httpserver for responding to http requests
- wasmcloud:httpclient for fetching http resources from the internet
- wasmcloud:builtin:numbergen for generating a random number.

When the actor runs, open a web browser to the http port
(selected when linking to the httpserver)
## Prerequisites

Each time you refresh the page, you should get a random xkcd comic!
[Install wash](https://wasmcloud.com/docs/installation)

To use this actor:
_These instructions will be simpler when the providers
are published to a public registry_
## Running this example

```shell
# start wasmcloud host, nats, and a registry
# (use the docker-compose.yml file from the sdk)
# docker-compose up -d

# compile and generate signed wasm file for this actor
make
# push to local registry and start the actor
make push
make start

# install and start httpserver provider
cd path/to/capability-providers/httpserver-rs
make
make push
make start
make inspect
# get the provider id (starting with 'V') and paste it into the Makefile for HTTPSERVER_PROVIDER_ID

# install and start httpclient provider
cd path/to/capability-providers/httpclient
make
make push
make start
make inspect
# get the provider id (starting with 'V') and paste it into the Makefile for HTTPCLIENT_PROVIDER_ID

# you should now be able to link them
make link

wash up -d
wash app deploy ./wadm.yaml
```

Once all providers and the actor are started and linked,
Expand Down
80 changes: 50 additions & 30 deletions actor/xkcd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@
//! then requests metadata for that comic from the xkcd site,
//! and generates and html page with the title and image url from the metadata.
//!
use serde::Deserialize;
use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::json;

use wasmbus_rpc::actor::prelude::*;
use wasmcloud_interface_httpclient::{HttpClient, HttpClientSender, HttpRequest as CHttpRequest};
use wasmcloud_interface_httpserver::{HttpRequest, HttpResponse, HttpServer, HttpServerReceiver};
use wasmcloud_interface_numbergen::random_in_range;

// the highest numbered comic available. (around 2705 as of Nov 30, 2022)
mod ui;
use ui::Asset;

// the highest numbered comic available. (around 2705 as of Sep 4, 2023)
// xkcd comics are numbered continuously starting at 1
const MAX_COMIC_ID: u32 = 2705;
const MAX_COMIC_ID: u32 = 2822;

#[derive(Debug, Default, Actor, HealthResponder)]
#[services(Actor, HttpServer)]
Expand All @@ -24,17 +30,45 @@ struct XkcdActor {}
#[async_trait]
impl HttpServer for XkcdActor {
async fn handle_request(&self, ctx: &Context, req: &HttpRequest) -> RpcResult<HttpResponse> {
// all the work happens inside handle_inner.
// The purpose of this wrapper is to catch any errors generated
// by the inner function and turn them into a valid HttpResponse.
Ok(self
.handle_inner(ctx, req)
.await
.unwrap_or_else(|e| HttpResponse {
body: json!({ "error": e.to_string() }).to_string().into_bytes(),
status_code: 500,
..Default::default()
}))
match req.path.trim_start_matches('/') {
// Handle requests to retrieve comic data
"comic" =>
// all the work happens inside handle_inner.
// The purpose of this wrapper is to catch any errors generated
// by the inner function and turn them into a valid HttpResponse.
{
Ok(self
.handle_inner(ctx, req)
.await
.unwrap_or_else(|e| HttpResponse {
body: json!({ "error": e.to_string() }).to_string().into_bytes(),
status_code: 500,
..Default::default()
}))
}
ui_asset_path => {
let path = if ui_asset_path.is_empty() {
"index.html"
} else {
ui_asset_path
};
// Request for UI asset
Ok(Asset::get(path)
.map(|asset| {
let mut header = HashMap::new();
if let Some(content_type) = mime_guess::from_path(path).first() {
header
.insert("Content-Type".to_string(), vec![content_type.to_string()]);
}
HttpResponse {
status_code: 200,
header,
body: Vec::from(asset.data),
}
})
.unwrap_or_else(|| HttpResponse::not_found()))
}
}
}
}

Expand All @@ -59,22 +93,8 @@ impl XkcdActor {
// and build html page
let info = serde_json::from_slice::<XkcdMetadata>(&resp.body)
.map_err(|e| tag_err("decoding metadata", e))?;
let html = format!(
r#"<!DOCTYPE html>
<html>
<head>
<title>Your XKCD random comic</title>
</head>
<body>
<h1>{}</h1>
<img src="{}"/>
</body>
</html>
"#,
&info.title, &info.img
);
let resp = HttpResponse {
body: html.into_bytes(),
body: serde_json::to_vec(&info).unwrap_or_default(),
..Default::default()
};
Ok(resp)
Expand All @@ -83,7 +103,7 @@ impl XkcdActor {

/// Metadata returned as json
/// (this is a subset of the full metadata, but we only need two fields)
#[derive(Deserialize)]
#[derive(Deserialize, Serialize)]
struct XkcdMetadata {
title: String,
img: String,
Expand Down
5 changes: 5 additions & 0 deletions actor/xkcd/src/ui.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use rust_embed::RustEmbed;

#[derive(RustEmbed)]
#[folder = "./ui/build"]
pub struct Asset;
20 changes: 20 additions & 0 deletions actor/xkcd/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

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

npm-debug.log*
yarn-debug.log*
yarn-error.log*
6 changes: 6 additions & 0 deletions actor/xkcd/ui/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"arrowParens": "avoid",
"trailingComma": "es5",
"singleQuote": true,
"semi": true
}
Loading

0 comments on commit a1c4db8

Please sign in to comment.