Skip to content

Commit

Permalink
feat: homestar client (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomrdias committed Nov 7, 2023
1 parent e0d1fd7 commit 1c7376c
Show file tree
Hide file tree
Showing 33 changed files with 1,944 additions and 179 deletions.
2 changes: 1 addition & 1 deletion .github/release-please-config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"separate-pull-requests": true,
"packages": {
"packages/package1": {},
"packages/homestar": {},
"packages/eslint-config": {}
}
}
2 changes: 1 addition & 1 deletion .github/release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"packages/package1": "0.0.1",
"packages/homestar": "0.0.1",
"packages/eslint-config": "0.0.3"
}
33 changes: 33 additions & 0 deletions .github/workflows/homestar.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: homestar
env:
CI: true
FORCE_COLOR: 1
on:
push:
branches: [main]
paths:
- 'packages/homestar/**'
- .github/workflows/homestar.yml
- pnpm-lock.yaml
pull_request:
paths:
- 'packages/homestar/**'
- .github/workflows/homestar.yml
- pnpm-lock.yaml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: latest
- uses: actions/setup-node@v3
with:
node-version: lts/*
cache: pnpm
- run: pnpm install
- run: pnpm run build
- run: pnpm -r --filter @fission-codes/homestar run lint
- run: pnpm -r --filter @fission-codes/homestar run test
- run: pnpm -r --filter @fission-codes/homestar exec depcheck
6 changes: 4 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ jobs:
npm:
needs: release
if: |
contains(fromJson(needs.release.outputs.paths_released), 'packages/eslint-config')
contains(fromJson(needs.release.outputs.paths_released), 'packages/eslint-config') ||
contains(fromJson(needs.release.outputs.paths_released), 'packages/homestar')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -52,5 +53,6 @@ jobs:
docs:
needs: release
if: |
contains(fromJson(needs.release.outputs.paths_released), 'packages/eslint-config')
contains(fromJson(needs.release.outputs.paths_released), 'packages/eslint-config')||
contains(fromJson(needs.release.outputs.paths_released), 'packages/homestar')
uses: ./.github/workflows/reusable-docs.yml
49 changes: 29 additions & 20 deletions packages/package1/package.json → packages/homestar/package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
{
"name": "package1",
"name": "@fission-codes/homestar",
"type": "module",
"version": "0.0.1",
"description": "Example package description.",
"description": "Homestart Client.",
"author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
"license": "MIT",
"homepage": "https://github.com/fission-codes/stack/tree/main/packages/homestar",
"repository": {
"url": "hugomrdias/hd-template",
"directory": "packages/package1"
"url": "fission-codes/stack",
"directory": "packages/homestar"
},
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"default": "./src/index.js"
},
"./crypto": {
"types": "./dist/src/crypto.d.ts",
"browser": "./src/crypto-browser.js",
"default": "./src/crypto.js"
"./workflow": {
"types": "./dist/src/workflow.d.ts",
"default": "./src/workflow.js"
}
},
"main": "src/index.js",
"types": "dist/src/index.d.ts",
"browser": {
"crypto": false,
"./src/crypto.js": "./src/crypto-browser.js"
},
"typesVersions": {
"*": {
"module1": [
"dist/src/crypto"
"workflow": [
"dist/src/workflow"
]
}
},
Expand All @@ -42,16 +38,29 @@
"lint": "tsc --build && eslint . && prettier --check '**/*.{js,ts,yml,json}' --ignore-path ../../.gitignore",
"build": "tsc --build",
"test": "pnpm run test:node && pnpm run test:browser",
"test:node": "mocha 'test/**/!(*.browser).test.js'",
"test:node": "playwright-test 'test/**/!(*.browser).test.js' --mode node",
"test:browser": "playwright-test 'test/**/!(*.node).test.js'"
},
"dependencies": {
"@ipld/dag-cbor": "^9.0.6",
"@ipld/dag-json": "^10.1.5",
"@multiformats/sha3": "^3.0.1",
"emittery": "^1.0.1",
"iso-websocket": "^0.1.5",
"multiformats": "^12.1.3",
"object-path": "^0.11.8",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/assert": "^1.5.8",
"@types/mocha": "^10.0.3",
"@types/get-value": "^3.0.5",
"@types/json-templates": "^3.0.3",
"@types/node": "^20.8.9",
"assert": "^2.1.0",
"mocha": "^10.2.0",
"playwright-test": "^12.4.3"
"@types/object-path": "^0.11.4",
"p-defer": "^4.0.0",
"playwright-test": "^12.4.3",
"type-fest": "^4.6.0",
"unws": "^0.2.4",
"ws": "^8.14.2"
},
"publishConfig": {
"provenance": true
Expand Down
69 changes: 69 additions & 0 deletions packages/homestar/pw-test.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { WebSocketServer } from 'ws'

/**
* @type {import("ws").WebSocketServer}
*/
let server

/** @type {import('playwright-test').RunnerOptions} */
const config = {
beforeTests() {
server = new WebSocketServer({
port: 8080,
})

server.on('connection', (socket, req) => {
const url = new URL(req.url, `http://${req.headers.host}`)
// const query = url.searchParams

if (url.pathname.startsWith('/notify')) {
socket.send(
JSON.stringify({
jsonrpc: '2.0',
method: 'notify',
params: ['notify'],
})
)
}

socket.on('error', console.error)

socket.on('message', (data) => {
const msg = JSON.parse(data.toString())
if (url.pathname.startsWith('/echo')) {
return socket.send(
JSON.stringify({
jsonrpc: '2.0',
result: msg.params[0],
id: msg.id,
})
)
}
if (url.pathname.startsWith('/null-id')) {
return socket.send(
JSON.stringify({
jsonrpc: '2.0',
result: msg.params[0],
// eslint-disable-next-line unicorn/no-null
id: null,
})
)
}

if (url.pathname.startsWith('/timeout')) {
// delay response
}
})
})
},

afterTests() {
for (const client of server.clients) {
client.terminate()
}
server.removeAllListeners()
server.close()
},
}

export default config
48 changes: 48 additions & 0 deletions packages/homestar/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Package 1 [![NPM Version](https://img.shields.io/npm/v/iso-base.svg)](https://www.npmjs.com/package/iso-base) [![License](https://img.shields.io/npm/l/iso-base.svg)](https://github.com/hugomrdias/iso-repo/blob/main/license) [![iso-base](https://github.com/hugomrdias/iso-repo/actions/workflows/iso-base.yml/badge.svg)](https://github.com/hugomrdias/iso-repo/actions/workflows/iso-base.yml)

## Installation

```bash
pnpm install package1
```

## Usage

```js
import { module } from 'package1'
```

## TODO

- CID in the `run` prop dag-cbor CID v1 (sha3-256)
- count workflow tasks and match receipts then unsub with unsubscribe_run_workflow and client events
-

```rust
/// Health endpoint.
pub(crate) const HEALTH_ENDPOINT: &str = "health";
/// Metrics endpoint for prometheus / openmetrics polling.
pub(crate) const METRICS_ENDPOINT: &str = "metrics";
/// Run a workflow and subscribe to that workflow's events.
#[cfg(feature = "websocket-notify")]
pub(crate) const SUBSCRIBE_RUN_WORKFLOW_ENDPOINT: &str = "subscribe_run_workflow";
/// Unsubscribe from a workflow's events.
#[cfg(feature = "websocket-notify")]
pub(crate) const UNSUBSCRIBE_RUN_WORKFLOW_ENDPOINT: &str = "unsubscribe_run_workflow";
/// Subscribe to network events.
#[cfg(feature = "websocket-notify")]
pub(crate) const SUBSCRIBE_NETWORK_EVENTS_ENDPOINT: &str = "subscribe_network_events";
/// Unsubscribe from network events.
#[cfg(feature = "websocket-notify")]
pub(crate) const UNSUBSCRIBE_NETWORK_EVENTS_ENDPOINT: &str = "unsubscribe_network_events";
```

## Contributing

Read contributing guidelines [here](../../.github/CONTRIBUTING.md).

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/hugomrdias/hd-template)

## License

[MIT](../../license) © [Hugo Dias](http://hugodias.me)
96 changes: 96 additions & 0 deletions packages/homestar/src/channel/channel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* eslint-disable unicorn/no-null */
import Emittery from 'emittery'

/**
* @typedef {import('./codecs/types').CodecType} CodecType
* @typedef {import('./codecs/types').Codec} Codec
*/

/**
* @template {Codec} C
* @typedef {import('./types').IChannel<C>} IChannel
*/

/**
* @class Channel
* @template {Codec} C
* @implements {IChannel<C>}
* @extends {Emittery<import('./types').ChannelEvents<C>>}
*/
export class Channel extends Emittery {
/** @type {Map<string, {resolve: (value: any) => void}>} */
#queue = new Map()
/**
*
* @param {import('./types').ChannelOptions<C>} opts
*/
constructor(opts) {
super()
/** @type {Required<import('./types').ChannelOptions<C>>} */
this.opts = { timeout: 5000, ...opts }

this.opts.transport.on('response', this.#handleResponse)
}

/**
*
* @param {string} id
* @param {number} [timeout]
*/
#queueRequest(id, timeout) {
return new Promise((resolve, reject) => {
if (timeout) {
setTimeout(() => {
this.#queue.delete(id)

resolve({
error: new Error('Timeout'),
})
}, timeout)
}
this.#queue.set(id, { resolve })
})
}

/**
*
* @param {string | ArrayBuffer} data
*/
#handleResponse = (data) => {
const { id, data: decoded } = this.opts.codec.decode(data)

if (id === undefined && decoded.result) {
this.emit('notification', decoded.result)
}

if (id === undefined && decoded.error) {
this.emit('error', new Error('Codec Error', { cause: decoded }))
}

if (decoded && id != null) {
const prom = this.#queue.get(id.toString())
if (prom) {
prom.resolve(decoded)
}
}

if (id === null) {
this.emit('error', new Error('Null ID', { cause: decoded }))
}
}

/** @type {IChannel<C>['request']} */
request(data, timeout = this.opts.timeout) {
const { id, data: encoded } = this.opts.codec.encode(data)

this.opts.transport.send(encoded, timeout)

return this.#queueRequest(id.toString(), timeout)
}

close() {
this.#queue.clear()
this.opts.transport.off('response', this.#handleResponse)
this.opts.transport.close()
}
}
Loading

0 comments on commit 1c7376c

Please sign in to comment.