Skip to content

Commit 56c0cfc

Browse files
authored
fix(client): pass bytes to POST /query properly (#265)
1 parent 806df9d commit 56c0cfc

File tree

7 files changed

+163
-73
lines changed

7 files changed

+163
-73
lines changed

packages/client/api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,12 @@ export class MainAPI {
167167
}
168168

169169
public async query(query: dm.SignedQuery): Promise<dm.QueryResponse> {
170+
const bytes = getCodec(dm.SignedQuery).encode(query)
170171
return this.http
171172
.getFetch()(urlJoinPath(this.http.toriiBaseURL, ENDPOINT_QUERY), {
172173
method: 'POST',
173-
body: [getCodec(dm.SignedQuery).encode(query)],
174+
// FIXME: see `transaction` method, same issue
175+
body: bytes as unknown as BodyInit,
174176
})
175177
.then(handleQueryResponse)
176178
}

tests/browser/cypress/e2e/main.cy.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ it('Register new domain and wait until commitment', () => {
99
// wait for the genesis block
1010
cy.get('h3').contains('Status').closest('div').contains('Blocks: 2')
1111

12-
cy.get('button').contains('Listen').click().contains('Stop')
12+
cy.get('button').contains('Listen').click()
13+
cy.get('li.active-events').contains('Events: true')
14+
cy.get('li.active-blocks').contains('Blocks: true')
1315

1416
cy.get('input').type('bob')
1517
cy.get('button').contains('Register domain').click()
@@ -21,10 +23,26 @@ it('Register new domain and wait until commitment', () => {
2123
const EXPECTED_EVENTS = 8
2224

2325
// And all events are caught
24-
cy.get('ul.events-list')
26+
cy.get('ul.events')
2527
.children('li')
2628
.should('have.length', EXPECTED_EVENTS)
2729
.last()
28-
.contains('Block')
30+
.contains('Block (height=4)')
2931
.contains('Applied')
32+
33+
// And all blocks too
34+
cy.get('ul.blocks')
35+
.children('li')
36+
.should('have.length', 4)
37+
.first().contains('1')
38+
.parent()
39+
.last().contains('4')
40+
41+
cy.get('button').contains('Query domains').click()
42+
43+
// our registered domain appears
44+
cy.get('ul.domains')
45+
.children('li')
46+
.should('have.length', 3)
47+
.first().contains('bob')
3048
})

tests/browser/src/App.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
<script setup lang="ts">
22
import CreateDomain from './components/CreateDomain.vue'
3-
import EventListener from './components/EventListener.vue'
3+
import Listener from './components/Listener.vue'
44
import StatusChecker from './components/StatusChecker.vue'
5+
import QueryDomains from './components/QueryDomains.vue'
56
</script>
67

78
<template>
89
<StatusChecker />
910
<hr>
1011
<CreateDomain />
1112
<hr>
12-
<EventListener />
13+
<QueryDomains />
14+
<hr>
15+
<Listener />
1316
</template>
1417

1518
<style lang="scss">

tests/browser/src/components/CreateDomain.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const { state, run: registerDomain } = useTask(() =>
1313
dm.InstructionBox.Register.Domain({ id: new dm.Name(domainName.value), logo: null, metadata: [] }),
1414
]),
1515
)
16-
.submit({ verify: true }),
16+
.submit({ verify: true })
1717
)
1818
</script>
1919

@@ -25,6 +25,6 @@ const { state, run: registerDomain } = useTask(() =>
2525
<button @click="registerDomain()">Register domain{{ state.pending ? '...' : '' }}</button>
2626
</p>
2727

28-
{{ state }}
28+
{{ state }}
2929
</div>
3030
</template>

tests/browser/src/components/EventListener.vue

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import { useTask } from '@vue-kakuyaku/core'
4+
import { client } from '../client.ts'
5+
import * as dm from '@iroha/core/data-model'
6+
7+
const { state, run: update } = useTask(() =>
8+
client.find.domains()
9+
.executeAll()
10+
)
11+
</script>
12+
13+
<template>
14+
<div>
15+
<h3>Domains</h3>
16+
<p>
17+
<button @click="update()">Query domains</button>
18+
</p>
19+
20+
<ul class="domains" v-if="state.fulfilled">
21+
<li v-for="x in state.fulfilled.value">
22+
{{ x.id.value }}
23+
</li>
24+
</ul>
25+
</div>
26+
</template>

0 commit comments

Comments
 (0)