Skip to content

Commit

Permalink
refactor(client): use channel in store
Browse files Browse the repository at this point in the history
  • Loading branch information
Kalovelo committed Jul 15, 2022
1 parent 31e421b commit 69c04c4
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 78 deletions.
25 changes: 16 additions & 9 deletions client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@ import Header from './components/Header.vue';
import RockPaperScissor from './components/RockPaperScissor.vue';
import PopUp from './components/PopUp.vue';
import { useChannelStore } from './stores/channel';
import { onBeforeUnmount, shallowRef } from 'vue';
import { returnCoinsToFaucet } from './sdk/sdk';
import { SdkService } from './sdk/sdkService';
import { onBeforeUnmount, onMounted, toRaw } from 'vue';
import { getSdk, returnCoinsToFaucet } from './sdk/sdk';
import { ChannelService } from './sdk/sdkService';
import { AeSdk } from '@aeternity/aepp-sdk';
const channelStore = useChannelStore();
const sdkService = shallowRef(new SdkService());
async function initChannel() {
await sdkService.value.initializeChannel();
if (!channelStore.channelService) {
throw new Error('SDK is not initialized');
}
await channelStore.channelService.initializeChannel();
}
onMounted(async () => {
channelStore.channelService = new ChannelService(await getSdk());
});
onBeforeUnmount(async () => {
if (sdkService.value.sdk) {
await returnCoinsToFaucet(sdkService.value.sdk);
if (channelStore.channelService?.sdk) {
await returnCoinsToFaucet(toRaw(channelStore.channelService.sdk) as AeSdk);
}
});
</script>
Expand All @@ -27,10 +34,10 @@ onBeforeUnmount(async () => {
<PopUp />
<Header />
<ChannelInitialization
v-if="!channelStore.channelIsOpen"
v-if="!channelStore.channelService?.isOpen"
@initializeChannel="initChannel()"
/>
<RockPaperScissor v-if="channelStore.channelIsOpen" />
<RockPaperScissor v-if="channelStore.channelService?.isOpen" />
<TransactionsList />
</template>

Expand Down
6 changes: 3 additions & 3 deletions client/src/components/ChannelInitialization.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const title = computed(() =>
);
const errorMessage = computed(() =>
channelStore.error
? `Error ${channelStore.error.status}: ${channelStore.error.statusText}, ${channelStore.error.message}`
channelStore.channelService?.error
? `Error ${channelStore.channelService?.error.status}: ${channelStore.channelService?.error.statusText}, ${channelStore.channelService?.error.message}`
: ''
);
Expand Down Expand Up @@ -54,7 +54,7 @@ async function openStateChannel(): Promise<void> {
text="Start game"
/>
</div>
<LoadingAnimation v-else-if="!channelStore.error" />
<LoadingAnimation v-else-if="!channelStore.channelService?.error" />
<p v-else>
{{ errorMessage }}
</p>
Expand Down
15 changes: 10 additions & 5 deletions client/src/components/Header.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
<script setup lang="ts">
import { useChannelStore } from '../stores/channel';
import PlayerInfo from './PlayerInfo.vue';
const userBalance = undefined;
const botBalance = undefined;
const channelStore = useChannelStore();
</script>

<template>
<div class="header">
<PlayerInfo name="You" :balance="userBalance" />
<PlayerInfo
name="You"
:balance="channelStore.channelService?.balances.user"
/>
<div class="center"></div>
<PlayerInfo name="Bot" :balance="botBalance" />
<PlayerInfo
name="Bot"
:balance="channelStore.channelService?.balances.bot"
/>
</div>
</template>

Expand Down
12 changes: 8 additions & 4 deletions client/src/components/PlayerInfo.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<script setup lang="ts">
import { BigNumber } from 'bignumber.js';
defineProps<{
name: string;
balance?: number;
balance?: Omit<BigNumber, '_isBigNumber'>;
}>();
</script>

<template>
<div class="player-info">
<span class="name">{{ name }}</span>
<span class="balance" data-testid="balance" v-if="balance"
>{{ balance }} ae</span
>{{ balance.dividedBy(1e18) }} ae</span
>
</div>
</template>
Expand All @@ -27,8 +29,10 @@ defineProps<{
}
.balance {
font-size: 20px;
color: #de3f6b;
font-size: 30px;
text-align: right;
font-weight: 500;
color: var(--pink);
}
}
</style>
5 changes: 2 additions & 3 deletions client/src/components/TransactionsList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
import { computed, ref } from 'vue';
import { useChannelStore } from '../stores/channel';
import SingleTransaction, { Transaction } from './SingleTransaction.vue';
const transactions = ref<Transaction[]>([]);
const channelStore = useChannelStore();
const isMinimized = computed(() => !channelStore.channelIsOpen);
const isMinimized = computed(() => !channelStore.channelService?.isOpen);
</script>

<template>
Expand All @@ -15,7 +14,7 @@ const isMinimized = computed(() => !channelStore.channelIsOpen);
<button
class="autoplay"
aria-label="autoplay_button"
:disabled="!channelStore.channelIsOpen"
:disabled="!channelStore.channelService?.isOpen"
>
<img
class="icon"
Expand Down
89 changes: 54 additions & 35 deletions client/src/sdk/sdkService.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
import { BigNumber } from 'bignumber.js';
import { AeSdk, Channel } from '@aeternity/aepp-sdk';
import { ChannelOptions } from '@aeternity/aepp-sdk/es/channel/internal';
import { EncodedData } from '@aeternity/aepp-sdk/es/utils/encoder';
import { useChannelStore } from '../stores/channel';
import { getSdk, returnCoinsToFaucet } from './sdk';
import { returnCoinsToFaucet } from './sdk';
import { toRaw } from 'vue';

export class SdkService {
sdk?: AeSdk;
channel?: ChannelInstance;
export class ChannelService {
readonly sdk: AeSdk;
channelConfig?: ChannelOptions;
channel?: Channel;
isOpen = false;
error?: {
status: number;
statusText: string;
message: string;
} = undefined;
balances: {
user?: BigNumber;
bot?: BigNumber;
} = {
user: undefined,
bot: undefined,
};

async getChannelConfig(): Promise<ChannelOptions> {
const channelStore = useChannelStore();
constructor(sdk: AeSdk) {
this.sdk = sdk;
}

getChannelWithoutProxy() {
if (!this.channel) {
throw new Error('Channel is not initialized');
}
return toRaw(this.channel);
}

async fetchChannelConfig(): Promise<ChannelOptions> {
if (!this.sdk) throw new Error('SDK is not set');
const res = await fetch(import.meta.env.VITE_BOT_SERVICE_URL + '/open', {
method: 'POST',
Expand All @@ -25,7 +50,7 @@ export class SdkService {
const data = await res.json();

if (res.status != 200) {
channelStore.error = {
this.error = {
status: res.status,
statusText: res.statusText,
message: data.error || 'Error while fetching channel config',
Expand All @@ -36,36 +61,21 @@ export class SdkService {
}

async initializeChannel() {
this.sdk = await getSdk();
const channelStore = useChannelStore();

try {
channelStore.channelStatus = 'getting channel config...';
const channelConfig = await this.getChannelConfig();
if (channelConfig == null) {
this.channelConfig = await this.fetchChannelConfig();
if (this.channelConfig == null) {
throw new Error('Channel config is null');
}

channelStore.channelStatus = 'initializing channel...';
this.channel = new ChannelInstance(channelConfig, this.sdk);
await this.channel.openChannel();
await this.openChannel();
} catch (e) {
console.error(e);
}
}
}

export class ChannelInstance {
private channelConfig: ChannelOptions;
private channel: Channel | undefined;
private sdk: AeSdk;

constructor(channelConfig: ChannelOptions, sdk: AeSdk) {
this.channelConfig = channelConfig;
this.sdk = sdk;
}

async openChannel() {
if (!this.channelConfig) throw new Error('Channel config is not set');

this.channel = await Channel.initialize({
...this.channelConfig,
role: 'responder',
Expand All @@ -89,30 +99,39 @@ export class ChannelInstance {
if (!this.channel) {
throw new Error('Channel is not open');
}
return this.channel.status();
return this.getChannelWithoutProxy().status();
}

async signTx(tag: string, tx: EncodedData<'tx'>): Promise<EncodedData<'tx'>> {
// TODO show in pop up
return new Promise((resolve, reject) => {
resolve(Promise.resolve(this.sdk.signTransaction(tx, {})));
resolve(Promise.resolve(toRaw(this.sdk).signTransaction(tx, {})));
reject(new Error(`Error while signing tx with tag ${tag}`));
});
}

private registerEvents() {
if (this.channel) {
const channelStore = useChannelStore();

this.channel.on('statusChanged', (status) => {
channelStore.channelStatus = status;
this.getChannelWithoutProxy().on('statusChanged', (status) => {
if (status === 'disconnected') {
returnCoinsToFaucet(this.sdk);
}
if (status === 'open') {
channelStore.channelIsOpen = true;
this.isOpen = true;
// this.updateBalances();
}
});
}
}

// async updateBalances() {
// const { initiatorId, responderId } = this.channelConfig;
// if (!this.channel) throw new Error('Channel is not open');
// const balances = await toRaw(this.channel).balances([
// initiatorId,
// responderId,
// ]);
// this.balances.user = new BigNumber(balances[responderId]);
// this.balances.bot = new BigNumber(balances[initiatorId]);
// }
}
20 changes: 6 additions & 14 deletions client/src/stores/channel.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import { ChannelService } from './../sdk/sdkService';
import { defineStore } from 'pinia';

interface ChannelStore {
channelIsOpen: boolean;
channelStatus: string;
error?: {
status: number;
statusText: string;
message: string;
};
channelService?: ChannelService;
}

export const useChannelStore = defineStore('channel', {
state: () =>
({
channelIsOpen: false,
channelStatus: '',
error: undefined,
} as ChannelStore),
export const useChannelStore = defineStore<'channel', ChannelStore>('channel', {
state: () => ({
channelService: undefined,
}),
});
7 changes: 5 additions & 2 deletions client/tests/player-info.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BigNumber } from 'bignumber.js';
import { render } from '@testing-library/vue';
import { describe, it, expect } from 'vitest';
import PlayerInfo from '../src/components/PlayerInfo.vue';

const mockPlayerInfoNoBalance = { name: 'You' };
const mockPlayerInfo = { name: 'You', balance: 100 };
const mockPlayerInfo = { name: 'You', balance: new BigNumber(3) };

describe('Show player info', () => {
expect(PlayerInfo).toBeTruthy();
Expand All @@ -27,7 +28,9 @@ describe('Show player info', () => {
const playerName = playerInfo.getByText(mockPlayerInfo.name);
expect(playerName).toBeTruthy();

const playerBalance = playerInfo.getByText(`${mockPlayerInfo.balance} ae`);
const playerBalance = playerInfo.getByText(
`${mockPlayerInfo.balance.dividedBy(1e18)} ae`
);
expect(playerBalance).toBeTruthy();
});
});
6 changes: 3 additions & 3 deletions server/src/services/bot/bot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export const channelPool = new WeakSet<Channel>();

export const mutualChannelConfiguration = {
url: process.env.WS_URL ?? 'ws://localhost:3014/channel',
pushAmount: 1,
initiatorAmount: new BigNumber('3e18'),
responderAmount: new BigNumber('3e18'),
pushAmount: 0,
initiatorAmount: new BigNumber('4.5e18'),
responderAmount: new BigNumber('4.5e18'),
channelReserve: 2,
lockPeriod: 10,
debug: false,
Expand Down

0 comments on commit 69c04c4

Please sign in to comment.