|
| 1 | +<script setup lang="ts"> |
| 2 | +import { computed, onBeforeUnmount, onScopeDispose, Ref, ref, shallowReactive, shallowRef, watchEffect } from 'vue' |
| 3 | +import type { SetupEventsReturn } from '@iroha/client' |
| 4 | +import * as dm from '@iroha/core/data-model' |
| 5 | +import { match, P } from 'ts-pattern' |
| 6 | +import { client } from '../client.ts' |
| 7 | +import { useDeferredScope, useTask, wheneverFulfilled } from '@vue-kakuyaku/core' |
| 8 | +
|
| 9 | +const events = useDeferredScope<{ events: string[]; active: Ref<boolean> }>() |
| 10 | +const blocks = useDeferredScope<{ blocks: string[]; active: Ref<boolean> }>() |
| 11 | +
|
| 12 | +function setupEvents() { |
| 13 | + events.setup(() => { |
| 14 | + const task = useTask(() => |
| 15 | + client.events({ |
| 16 | + filters: [ |
| 17 | + dm.EventFilterBox.Pipeline.Block({ height: null, status: null }), |
| 18 | + dm.EventFilterBox.Pipeline.Transaction({ status: null, hash: null, blockHeight: null }), |
| 19 | + ], |
| 20 | + }), { immediate: true }) |
| 21 | +
|
| 22 | + const events = shallowReactive<string[]>([]) |
| 23 | + const active = ref(false) |
| 24 | +
|
| 25 | + wheneverFulfilled(task.state, (listener) => { |
| 26 | + active.value = true |
| 27 | + listener.ee.on('event', (event) => { |
| 28 | + events.push( |
| 29 | + match(event) |
| 30 | + .returnType<string>() |
| 31 | + .with( |
| 32 | + { kind: 'Pipeline', value: { kind: 'Block', value: P.select() } }, |
| 33 | + ({ status, header }) => `Block (height=${header.height.value}): ${status.kind}`, |
| 34 | + ) |
| 35 | + .with( |
| 36 | + { kind: 'Pipeline', value: { kind: 'Transaction', value: P.select() } }, |
| 37 | + ({ hash, status }) => `Transaction (${hash.payload.hex().slice(0, 6)}...): ${status.kind}`, |
| 38 | + ) |
| 39 | + .otherwise(({ kind }) => { |
| 40 | + throw new Error(`This should not appear with given filters: ${kind}`) |
| 41 | + }), |
| 42 | + ) |
| 43 | + }) |
| 44 | + }, { immediate: true }) |
| 45 | +
|
| 46 | + onScopeDispose(() => task.state.fulfilled?.value?.stop()) |
| 47 | +
|
| 48 | + return { events, active } |
| 49 | + }) |
| 50 | +} |
| 51 | +
|
| 52 | +function setupBlocks() { |
| 53 | + blocks.setup(() => { |
| 54 | + const task = useTask(() => client.blocks(), { immediate: true }) |
| 55 | +
|
| 56 | + const blocks = shallowReactive<string[]>([]) |
| 57 | + const active = ref(false) |
| 58 | +
|
| 59 | + wheneverFulfilled(task.state, async (listener) => { |
| 60 | + active.value = true |
| 61 | + for await (const block of listener.stream) { |
| 62 | + blocks.push(String(block.value.payload.header.height.value)) |
| 63 | + } |
| 64 | + active.value = false |
| 65 | + }) |
| 66 | +
|
| 67 | + onScopeDispose(() => task.state.fulfilled?.value?.stop()) |
| 68 | +
|
| 69 | + return { blocks, active } |
| 70 | + }) |
| 71 | +} |
| 72 | +
|
| 73 | +function setupListeners() { |
| 74 | + setupEvents() |
| 75 | + setupBlocks() |
| 76 | +} |
| 77 | +</script> |
| 78 | + |
| 79 | +<template> |
| 80 | + <div> |
| 81 | + <h3>Listening</h3> |
| 82 | + |
| 83 | + <p> |
| 84 | + <button @click="setupListeners()"> |
| 85 | + Listen |
| 86 | + </button> |
| 87 | + |
| 88 | + <ul> |
| 89 | + <li class="active-events">Events: {{ events.scope.value?.expose.active.value ?? false }}</li> |
| 90 | + <li class="active-blocks">Blocks: {{ blocks.scope.value?.expose.active.value ?? false }}</li> |
| 91 | + </ul> |
| 92 | + </p> |
| 93 | + |
| 94 | + <ul class="events"> |
| 95 | + <li v-for="(item, i) in events.scope.value?.expose.events ?? []" :key="i"> |
| 96 | + {{ item }} |
| 97 | + </li> |
| 98 | + </ul> |
| 99 | + |
| 100 | + <ul class="blocks"> |
| 101 | + <li v-for="(item, i) in blocks.scope.value?.expose.blocks ?? []" :key="i"> |
| 102 | + {{ item }} |
| 103 | + </li> |
| 104 | + </ul> |
| 105 | + </div> |
| 106 | +</template> |
0 commit comments