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

PoC of WASM pretty print of CloudEvents #1

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.compile.nullAnalysis.mode": "automatic"
}
38 changes: 37 additions & 1 deletion frontend/package-lock.json

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

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"adm-zip": "^0.5.10",
"colorette": "^2.0.19",
"react-scripts": "5.0.1",
"ts-node": "^10.9.1"
"ts-node": "^10.9.1",
"wasm-oci": "^0.1.3"
},
"dependencies": {
"@types/node": "^18.15.0",
Expand Down
161 changes: 124 additions & 37 deletions frontend/scripts/webjar.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,134 @@
import AdmZip from 'adm-zip'
import fs from 'fs'
import { green, yellow } from 'colorette'
import fs from 'fs/promises'
import os from 'os'
import { green, yellow, cyan, magenta, Color, blue, white } from 'colorette'
import { WasmRegistry, Image } from 'wasm-oci'

const coords = {
type Packager = (packer: Packer, log: Logger) => Promise<void>

interface Packer {
/**
* Adds a file from the disk to the archive.
* @param localPath Path to a file on disk.
* @param zipPath Path to a directory in the archive. Defaults to the empty
* string.
* @param zipName Name for the file.
* @param comment Comment to be attached to the file
*/
addLocalFile(localPath: string, zipPath?: string, zipName?: string, comment?: string): void
/**
* Adds a local directory and all its nested files and directories to the
* archive.
* @param localPath Path to a folder on disk.
* @param zipPath Path to a folder in the archive. Default: `""`.
* @param filter RegExp or Function if files match will be included.
*/
addLocalFolder(localPath: string, zipPath?: string, filter?: (path: string) => boolean): void
/**
* Allows you to create a entry (file or directory) in the zip file.
* If you want to create a directory the `entryName` must end in `"/"` and a `null`
* buffer should be provided.
* @param entryName Entry path.
* @param content Content to add to the entry; must be a 0-length buffer
* for a directory.
* @param comment Comment to add to the entry.
* @param attr Attribute to add to the entry.
*/
addFile(entryName: string, content: Buffer, comment?: string, attr?: number): void
}

interface Webjar {
group: string
artifact: string
version: string
color: Color,
build: Packager
}

const webjars: Webjar[] = [{
group: 'com.redhat.openshift.knative.showcase',
artifact: 'frontend',
version: 'main',
color: cyan,
build: async p => {
p.addLocalFolder('./build', 'META-INF/resources', (path) => {
return !path.includes('index.html')
})
p.addLocalFile('./build/index.html', 'META-INF/resources', 'home.html')
}
}, {
group: 'com.redhat.openshift.knative.showcase',
artifact: 'cloudevents-pp-wasm',
version: 'main',
color: magenta,
build: async (p, log) => {
const tmpDir = os.tmpdir()
const tmp = await fs.mkdtemp(`${tmpDir}/wasm-oci-`)
const reg = new WasmRegistry(tmp)
const image = Image.parse('quay.io/cardil/cloudevents-pretty-print@sha256:01b30983dda5eb42a8baefb523eb50d7d0e539fb10d7ab9498a2a59f35036afb')
log(`Pulling image: ${green(image.toString())}`)
const wasm = await reg.pull(image)
p.addFile('META-INF/cloudevents-pretty-print.wasm', await fs.readFile(wasm.file), 'Wasm')
await fs.rm(tmp, { recursive: true })
}
}]

type Logger = (message?: any, ...optionalParams: any[]) => void

function createLogger(name: string): Logger {
return (msg) => {
console.log(`[${name}] ${msg}`)
}
}

const jarDir = `${process.env.HOME}/.m2/repository/` +
`${coords.group.replace(/\./g, '/')}/` +
`${coords.artifact}/` + coords.version
const jarPath = `${jarDir}/${coords.artifact}-${coords.version}.jar`
const pomPath = `${jarDir}/${coords.artifact}-${coords.version}.pom`

const pom = `<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>${coords.group}</groupId>
<artifactId>${coords.artifact}</artifactId>
<version>${coords.version}</version>
<packaging>jar</packaging>
// Build by: forntend/scripts/webjar.ts script
async function buildWebjar(webjar: Webjar) {
const log = createLogger(webjar.color(webjar.artifact))
const jarDir = `${process.env.HOME}/.m2/repository/` +
`${webjar.group.replace(/\./g, '/')}/` +
`${webjar.artifact}/` + webjar.version
const jarPath = `${jarDir}/${webjar.artifact}-${webjar.version}.jar`
const pomPath = `${jarDir}/${webjar.artifact}-${webjar.version}.pom`

const pom = `<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>${webjar.group}</groupId>
<artifactId>${webjar.artifact}</artifactId>
<version>${webjar.version}</version>
<packaging>jar</packaging>
// Build by: forntend/scripts/webjar.ts script
</project>
`
const zip = new AdmZip()
await webjar.build(zip, log)
zip.addFile(`META-INF/maven/${webjar.group}/${webjar.artifact}/pom.xml`, Buffer.from(pom))
zip.writeZip(jarPath)
log(`Created webjar: ${yellow(jarPath)}`)
await fs.writeFile(pomPath, pom)
log(`Created webjar POM: ${yellow(pomPath)}`)
log('To use it, add following to your pom.xml file:\n' + blue(
`
<dependency>
<groupId>${white(webjar.group)}</groupId>
<artifactId>${white(webjar.artifact)}</artifactId>
<version>${white(webjar.version)}</version>
</dependency>
`))
}

async function build() {
const ps : Promise<void>[] = []
for (const webjar of webjars) {
ps.push(buildWebjar(webjar))
}
await Promise.all(ps)
}

const zip = new AdmZip()
zip.addLocalFolder('./build', 'META-INF/resources', (path) => {
return !path.includes('index.html')
})
zip.addLocalFile('./build/index.html', 'META-INF/resources', 'home.html')
zip.addFile(`META-INF/maven/${coords.group}/${coords.artifact}/pom.xml`, Buffer.from(pom))
zip.writeZip(jarPath)
console.log(`Created webjar: ${yellow(jarPath)}`)
fs.writeFileSync(pomPath, pom)
console.log(`Created webjar POM: ${yellow(pomPath)}`)
console.log('\nTo use it, add following to your pom.xml file:\n\n' + green(
`
<dependency>
<groupId>${coords.group}</groupId>
<artifactId>${coords.artifact}</artifactId>
<version>${coords.version}</version>
</dependency>
`))
build()
.catch(e => {
console.error(e)
process.exit(1)
})
.then(() => process.exit(0))
10 changes: 10 additions & 0 deletions quarkus/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@
<artifactId>frontend</artifactId>
<version>main</version>
</dependency>
<dependency>
<groupId>com.redhat.openshift.knative.showcase</groupId>
<artifactId>cloudevents-pp-wasm</artifactId>
<version>main</version>
</dependency>
<dependency>
<groupId>io.github.kawamuray.wasmtime</groupId>
<artifactId>wasmtime-java</artifactId>
<version>0.14.0</version>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.redhat.openshift.knative.showcase.events;

import com.redhat.openshift.wasm.c.CString;
import io.cloudevents.CloudEvent;
import io.cloudevents.jackson.JsonFormat;
import io.quarkus.runtime.ShutdownEvent;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;

@ApplicationScoped
class Presenter {

private final PrettyPrintWasm wasm = new PrettyPrintWasm();

void onStop(@Observes ShutdownEvent ignored) {
wasm.close();
}

byte[] toJson(CloudEvent ce) {
var serializer = new JsonFormat();
return serializer.serialize(ce);
}

String present(CloudEvent ce) {
var json = toJson(ce);
var input = new CString(json);
var output = wasm.execute(input);
return output.toString();
}
}
Loading