የተቀላቀለ Kaigi በ JavaScript መተግበሪያ
Kaigi አንድ መተግበሪያ በኪስ ቦርሳ የተደገፉ የኦዲዮ / ቪዲዮ ስብሰባዎችን እንዲፈጥር ያስችለዋል ፣ የእነሱ የሕይወት ዑደት በ Iroha በኩል ይመዘገባል። አሳሹ አሁንም ሚዲያውን በ WebRTC ያስተናግዳል ፣ Torii እና Kaigi መመሪያዎችም ዘላቂ የመሰብሰቢያ መዝገብን ይሰጣሉ ፣ የተመሰጠረ የምልክት ሜታዳታ ፣ የግል ዝርዝር ድጋፍ እና አጠቃቀም ክስተቶች.
ይህ መመሪያ በ Iroha ዴሞ JavaScript መተግበሪያ ጥቅም ላይ የዋለውን አነስተኛ ውህደት ንድፍ ያሳያል:
- አስተላላፊው WebRTC አቅርቦቶችን እና መልሶችን ይፈጥራል ።
- አንድ ማመልከቻ ድልድይ ይለያል እና Kaigi ግብይቶች ያቀርባል
- የታመሙ የግብዣ አገናኞች ጥሪውን ID ብቻ ይሸከማሉ እና የግብዣ ምስጢራዊ ነው
- አስተናጋጅ Torii ለተሳታፊዎች የተደበዘዙ መልሶች የሚከታተል
ምሳሌዎቹ TypeScript ን ይጠቀማሉ እናም በኤሌክትሮን ፣ ደህንነቱ የተጠበቀ የጀርባ አወጣጥ ካለው አሳሽ ወይም Wallet ማራዘሚያ ካለው የድር መተግበሪያ ውስጥ ሊሠሩ እንዲችሉ ተጽፈዋል ።
ቅድመ ሁኔታዎች
አንተ ያስፈልግሃል:
- አንድ Kaigi-አቅም ያለው Torii መጨረሻ ነጥብ
- የአስተናጋጁ እና የእንግዳው መለያ
- ደህንነቱ የተጠበቀ የመተግበሪያ ድልድይ ወይም የኪስ ቦርሳ በኩል ወደ እያንዳንዱ መለያ ፊርማ ቁልፍ መዳረሻ
- የአሳሽ ካሜራ/ማይክሮፎን ፍቃዶች
- Node.js 20+ የሚጠቀሙ ከሆነ JavaScript ዲሞ ወይም ተወላጅ
@iroha/iroha-jsበቀጥታ የሚጣበቅ
ለሙሉ የሥራ ማጣቀሻ ከ Iroha ምንጭ ቼክ አጠገብ ያለውን ማሳያ ቅጅ:
mkdir iroha-wallet-workspace
cd iroha-wallet-workspace
git clone https://github.com/hyperledger-iroha/iroha.git
git clone https://github.com/soramitsu/iroha-demo-javascript.git
cd iroha/javascript/iroha_js
npm install
npm run build:native
npm run build:dist
cd ../../../iroha-demo-javascript
npm install
npm run devየ ማሳያውን ይጠቀሙ @iroha/iroha-js ከወንድም Iroha ምንጭ ማከማቻ. file: ተወላጅ ተያያዥነት በቀጥታ ያ ቼክአውት ይፈታል. iroha/javascript/iroha_js; ንጹህ የፓኬጅ ማውጫ በ Cargo የሚፈለገውን የሥራ ቦታ አይይዝም npm run build:native.
በ TAIRA ላይ የቀጥታ ስብሰባ ከማካሄድዎ በፊት ማሳያው የሚመረኮዝበትን የህዝብ ገጽ Torii ይፈትሹ:
TAIRA=https://taira.sora.org
curl -fsS "$TAIRA/health"
curl -fsS "$TAIRA/v1/kaigi/relays"
curl -fsS "$TAIRA/v1/kaigi/relays/health"እነዚህ ትዕዛዞች እንደሚያረጋግጡ TAIRA በሕይወት ነው እና ይህ Kaigi ተለጣፊ ቴሌሜትሪ ይገኛል. Kaigi ግብይቶች. CreateKaigi ወይም JoinKaigi የሙከራ ፍላጎቶች የገንዘብ ድጋፍ TAIRA ሂሳቦች እና በዴሞው ድልድይ ወይም ሌላ የኪስ ቦርሳ የተደገፈ ድልድይ በኩል ፊርማ ማድረግ.
ሥነ ሕንፃ
የ Kaigi ውህደት በሦስት ንብርብሮች ይከፈላል:
| ሽፋን | ኃላፊነት |
|---|---|
| UI | የመለያ ምርጫ፣ የስብሰባ ቅጽ፣ የጥሪ አገናኝ ማሳያ፣ የመገናኛ ብዙሃን መቆጣጠር |
| WebRTC | RTCPeerConnection፣ አካባቢያዊ ሚዲያዎች፣ አቅርቦትና መልስ መግለጫዎች |
| Iroha ድልድይ | ፊርማ፣ CreateKaigi, JoinKaigi, EndKaigi፣ የምልክት ምርጫ |
የመተግበሪያው ድልድይ የኤሌክትሮን ቅድመ ጭነት API ፣ የኪስ ቦርሳ ማራዘሚያ ወይም የጀርባ መጨረሻ ነጥብ ሊሆን ይችላል። አነስተኛ ወለል ለ UI ሊያጋልጥ ይገባል-
type KaigiMeetingPrivacy = "private" | "transparent";
type KaigiPeerIdentityReveal = "Hidden" | "RevealAfterJoin";
type KaigiSignalKeyPair = {
publicKeyBase64Url: string;
privateKeyBase64Url: string;
};
type KaigiDescription = {
type: "offer" | "answer";
sdp: string;
};
type KaigiMeeting = {
callId: string;
meetingCode: string;
title?: string;
hostAccountId?: string;
hostDisplayName?: string;
hostParticipantId?: string;
hostKaigiPublicKeyBase64Url: string;
scheduledStartMs: number;
expiresAtMs: number;
live: boolean;
ended: boolean;
privacyMode: KaigiMeetingPrivacy;
peerIdentityReveal: KaigiPeerIdentityReveal;
rosterRootHex: string;
offerDescription: { type: "offer"; sdp: string };
};
type KaigiSignal = {
entrypointHash: string;
callId: string;
participantId: string;
participantName: string;
createdAtMs: number;
answerDescription: { type: "answer"; sdp: string };
};
type KaigiBridge = {
generateKaigiSignalKeyPair(): KaigiSignalKeyPair;
createKaigiMeeting(input: {
toriiUrl: string;
chainId: string;
hostAccountId: string;
callId: string;
title?: string;
scheduledStartMs: number;
meetingCode: string;
inviteSecretBase64Url: string;
hostDisplayName: string;
hostParticipantId: string;
hostKaigiPublicKeyBase64Url: string;
offerDescription: { type: "offer"; sdp: string };
privacyMode: KaigiMeetingPrivacy;
peerIdentityReveal: KaigiPeerIdentityReveal;
}): Promise<{ hash: string }>;
getKaigiCall(input: {
toriiUrl: string;
callId: string;
inviteSecretBase64Url: string;
}): Promise<KaigiMeeting>;
joinKaigiMeeting(input: {
toriiUrl: string;
chainId: string;
participantAccountId: string;
callId: string;
hostAccountId?: string;
hostKaigiPublicKeyBase64Url: string;
participantId: string;
participantName: string;
walletIdentity?: string;
roomId: string;
privacyMode: KaigiMeetingPrivacy;
rosterRootHex: string;
answerDescription: { type: "answer"; sdp: string };
}): Promise<{ hash: string }>;
pollKaigiMeetingSignals(input: {
toriiUrl: string;
accountId: string;
callId: string;
hostKaigiKeys: KaigiSignalKeyPair;
afterTimestampMs?: number;
}): Promise<KaigiSignal[]>;
watchKaigiCallEvents(
input: { toriiUrl: string; callId: string },
onEvent: (event: { kind: string; callId: string }) => void | Promise<void>,
): Promise<string>;
endKaigiMeeting(input: {
toriiUrl: string;
chainId: string;
hostAccountId: string;
callId: string;
endedAtMs?: number;
}): Promise<{ hash: string }>;
};በማሳያ መተግበሪያ ውስጥ እነዚህ ድልድይ ዘዴዎች በ @iroha/iroha-js, አካባቢያዊ ፊርማ, የተመሰጠረ Kaigi ሜታዳታ, እና Torii ጥሪዎች ይተገበራሉ.
ረዳቶችን ይጋብዙ
Torii-ተኳሃኝ ጥሪ IDs በ domain.dataspace:meeting ቅጽ ይጠቀሙ። ማሳያው ለተፈጠሩ ስብሰባዎች kaigi.universal:<call-name> ይጠቀማል.
const KAIGI_WINDOW_MS = 24 * 60 * 60 * 1000;
const base64Url = (bytes: Uint8Array): string =>
btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/g, "");
export function createInviteSecret(): string {
const bytes = new Uint8Array(24);
crypto.getRandomValues(bytes);
return base64Url(bytes);
}
export function createMeetingCode(): string {
const bytes = new Uint8Array(8);
crypto.getRandomValues(bytes);
return base64Url(bytes).toLowerCase();
}
export function buildKaigiCallId(domain: string, meetingCode: string): string {
const qualifiedDomain = domain.includes(".") ? domain : `${domain}.universal`;
const safeCode = meetingCode
.toLowerCase()
.replace(/[^a-z0-9-]+/g, "-")
.replace(/^-|-$/g, "");
return `${qualifiedDomain}:kaigi-${safeCode || "meeting"}`;
}
export function buildInviteLink(input: {
callId: string;
inviteSecretBase64Url: string;
}): string {
const call = encodeURIComponent(input.callId);
const secret = encodeURIComponent(input.inviteSecretBase64Url);
return `iroha://kaigi/join?call=${call}&secret=${secret}`;
}
export function parseInviteLink(link: string): {
callId: string;
inviteSecretBase64Url: string;
} {
const url = new URL(link);
const callId = url.searchParams.get("call")?.trim();
const inviteSecretBase64Url = url.searchParams.get("secret")?.trim();
if (!callId || !inviteSecretBase64Url) {
throw new Error("Kaigi invite link is missing call or secret.");
}
return { callId, inviteSecretBase64Url };
}WebRTC ረዳቶች
አስተናጋጁ አንድ ቅናሽ ይፈጥራል ፣ በ CreateKaigi በኩል ያከማቻል ፣ እና የእንግዳውን መልስ ተግባራዊ ለማድረግ መስኮቱን ክፍት ይይዛል። እንግዱ የተመሰጠረውን ቅናሽ ይወስዳል ፣ መልስ ይፈጥራል እና መልሱን በ JoinKaigi ይለጥፋል ።
const rtcConfig: RTCConfiguration = {
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
};
export async function openLocalMedia(): Promise<MediaStream> {
return navigator.mediaDevices.getUserMedia({
audio: true,
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 24, max: 30 },
},
});
}
export function createPeer(localStream: MediaStream): RTCPeerConnection {
const peer = new RTCPeerConnection(rtcConfig);
for (const track of localStream.getTracks()) {
peer.addTrack(track, localStream);
}
return peer;
}
async function waitForIceGathering(peer: RTCPeerConnection): Promise<void> {
if (peer.iceGatheringState === "complete") {
return;
}
await new Promise<void>((resolve) => {
const done = () => {
if (peer.iceGatheringState === "complete") {
peer.removeEventListener("icegatheringstatechange", done);
resolve();
}
};
peer.addEventListener("icegatheringstatechange", done);
});
}
export async function createOfferDescription(
peer: RTCPeerConnection,
): Promise<{ type: "offer"; sdp: string }> {
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
await waitForIceGathering(peer);
const local = peer.localDescription;
if (!local?.sdp || local.type !== "offer") {
throw new Error("WebRTC offer was not created.");
}
return { type: "offer", sdp: local.sdp };
}
export async function createAnswerDescription(
peer: RTCPeerConnection,
offer: { type: "offer"; sdp: string },
): Promise<{ type: "answer"; sdp: string }> {
await peer.setRemoteDescription(offer);
const answer = await peer.createAnswer();
await peer.setLocalDescription(answer);
await waitForIceGathering(peer);
const local = peer.localDescription;
if (!local?.sdp || local.type !== "answer") {
throw new Error("WebRTC answer was not created.");
}
return { type: "answer", sdp: local.sdp };
}ዥረቶችን በ UI መደበኛ የቪዲዮ አካላት ጋር ያያይዙ:
export function attachKaigiMedia(input: {
peer: RTCPeerConnection;
localStream: MediaStream;
localVideo: HTMLVideoElement;
remoteVideo: HTMLVideoElement;
}): void {
input.localVideo.srcObject = input.localStream;
const remoteStream = new MediaStream();
input.remoteVideo.srcObject = remoteStream;
input.peer.addEventListener("track", (event) => {
if (event.streams[0]) {
input.remoteVideo.srcObject = event.streams[0];
return;
}
remoteStream.addTrack(event.track);
});
}አስተናጋጅ፦ የስብሰባ አገናኝ ይፍጠሩ
አስተናጋጅ ፍሰት:
- ክፍት ካሜራ እና ማይክሮፎን
- አንድ Kaigi ምልክት ቁልፍ ጥንድ ይፍጠሩ
- የ WebRTC ቅናሽ ያድርጉ
CreateKaigiማቅረብ- የታመቀ የግብዣ አገናኝ ያጋሩ
type AccountContext = {
accountId: string;
displayName: string;
};
type KaigiContext = {
bridge: KaigiBridge;
toriiUrl: string;
chainId: string;
};
export async function hostKaigiMeeting(input: {
context: KaigiContext;
account: AccountContext;
title?: string;
privacyMode?: KaigiMeetingPrivacy;
}): Promise<{
callId: string;
inviteLink: string;
peer: RTCPeerConnection;
localStream: MediaStream;
hostKaigiKeys: KaigiSignalKeyPair;
createdAtMs: number;
}> {
const { bridge, toriiUrl, chainId } = input.context;
const privacyMode = input.privacyMode ?? "private";
const scheduledStartMs = Date.now();
const meetingCode = createMeetingCode();
const callId = buildKaigiCallId("kaigi", meetingCode);
const inviteSecretBase64Url = createInviteSecret();
const hostKaigiKeys = bridge.generateKaigiSignalKeyPair();
const localStream = await openLocalMedia();
const peer = createPeer(localStream);
const offerDescription = await createOfferDescription(peer);
await bridge.createKaigiMeeting({
toriiUrl,
chainId,
hostAccountId: input.account.accountId,
callId,
title: input.title,
scheduledStartMs,
meetingCode,
inviteSecretBase64Url,
hostDisplayName: input.account.displayName,
hostParticipantId: "host",
hostKaigiPublicKeyBase64Url: hostKaigiKeys.publicKeyBase64Url,
offerDescription,
privacyMode,
peerIdentityReveal: "Hidden",
});
return {
callId,
inviteLink: buildInviteLink({ callId, inviteSecretBase64Url }),
peer,
localStream,
hostKaigiKeys,
createdAtMs: scheduledStartMs,
};
}inviteLink በእርስዎ UI ውስጥ ማሳየት. ተጠቃሚው መገልበጥ ይችላል, ሌላ ቦርሳ ውስጥ መክፈት, ወይም የመሳሰሉ መተግበሪያ መንገድ መለወጥ:
export function inviteRoute(inviteLink: string): string {
const invite = parseInviteLink(inviteLink);
return `/kaigi?call=${encodeURIComponent(invite.callId)}&secret=${encodeURIComponent(
invite.inviteSecretBase64Url,
)}`;
}እንግዳ፦ በስብሰባው ላይ ተገኝ
የእንግዳው ፍሰት:
- ግብዣውን ይመረምሩ
- ከ Torii የተመሰጠረ የጥሪ አቅርቦትን ያግኙ።
- የ WebRTC መልስ ይፍጠሩ
JoinKaigiከተመሰጠረ መልስ ሜታዳታ ጋር ያቅርቡ
export async function joinKaigiMeetingFromInvite(input: {
context: KaigiContext;
account: AccountContext;
inviteLink: string;
}): Promise<{
callId: string;
peer: RTCPeerConnection;
localStream: MediaStream;
}> {
const { bridge, toriiUrl, chainId } = input.context;
const { callId, inviteSecretBase64Url } = parseInviteLink(input.inviteLink);
const meeting = await bridge.getKaigiCall({
toriiUrl,
callId,
inviteSecretBase64Url,
});
if (meeting.ended) {
throw new Error("This Kaigi meeting has already ended.");
}
if (Date.now() > meeting.expiresAtMs) {
throw new Error("This Kaigi invite has expired.");
}
const localStream = await openLocalMedia();
const peer = createPeer(localStream);
const answerDescription = await createAnswerDescription(
peer,
meeting.offerDescription,
);
await bridge.joinKaigiMeeting({
toriiUrl,
chainId,
participantAccountId: input.account.accountId,
callId: meeting.callId,
hostAccountId: meeting.hostAccountId,
hostKaigiPublicKeyBase64Url: meeting.hostKaigiPublicKeyBase64Url,
participantId: "guest",
participantName: input.account.displayName,
roomId: meeting.callId,
privacyMode: meeting.privacyMode,
rosterRootHex: meeting.rosterRootHex,
answerDescription,
});
return { callId: meeting.callId, peer, localStream };
}ስብሰባው ግልፅ ከሆነ በመቀላቀል ጥያቄ ውስጥ የኪስ ቦርሳ ማሳያ ገመድ ማካተት ይችላሉ። ተጠቃሚው በግል ለመግለጽ ካልመረጠ በስተቀር ለግል ስብሰባዎች walletIdentity ን ያግኙ።
አስተናጋጅ፦ እንግዳው የሚሰጠውን መልስ ተግባራዊ አድርግ
ቀጥታ ስብሰባ ከተፈጠረ በኋላ አስተናጋጁ Kaigi ክስተቶችን መመልከት እና የተመሰጠረ የምላሽ ምልክቶች ምርጫ ማድረግ አለበት ። የመጀመሪያውን ትክክለኛ መልስ ለአስተናጋጁ የእኩዮች ግንኙነት ያድርጉ።
export async function watchForKaigiAnswer(input: {
context: KaigiContext;
hostAccountId: string;
callId: string;
hostKaigiKeys: KaigiSignalKeyPair;
createdAtMs: number;
peer: RTCPeerConnection;
onParticipant?: (signal: KaigiSignal) => void;
}): Promise<string | null> {
const { bridge, toriiUrl } = input.context;
const seenSignals = new Set<string>();
let lastSignalAtMs = input.createdAtMs;
const checkSignals = async (): Promise<boolean> => {
const signals = await bridge.pollKaigiMeetingSignals({
toriiUrl,
accountId: input.hostAccountId,
callId: input.callId,
hostKaigiKeys: input.hostKaigiKeys,
afterTimestampMs: lastSignalAtMs,
});
const next = signals.find(
(signal) => !seenSignals.has(signal.entrypointHash),
);
if (!next) {
return false;
}
seenSignals.add(next.entrypointHash);
lastSignalAtMs = Math.max(lastSignalAtMs, next.createdAtMs);
await input.peer.setRemoteDescription(next.answerDescription);
input.onParticipant?.(next);
return true;
};
if (await checkSignals()) {
return null;
}
return bridge.watchKaigiCallEvents(
{ toriiUrl, callId: input.callId },
async (event) => {
if (event.kind !== "ended") {
await checkSignals();
}
},
);
}የተመለሰውን የደንበኝነት ምዝገባ ID ያስቀምጡ ስለዚህ አስተናጋጁ ሲዘግይ ወይም ሲሄድ UI ተቆጣጣሪውን ሊያቆም ይችላል ።
ስብሰባው ያበቃል
ጥሪውን ከፈጠረው ተመሳሳይ አስተናጋጅ መለያ አቁሙ:
export async function endKaigi(input: {
context: KaigiContext;
hostAccountId: string;
callId: string;
peer?: RTCPeerConnection;
localStream?: MediaStream;
}): Promise<void> {
input.peer?.close();
input.localStream?.getTracks().forEach((track) => track.stop());
await input.context.bridge.endKaigiMeeting({
toriiUrl: input.context.toriiUrl,
chainId: input.context.chainId,
hostAccountId: input.hostAccountId,
callId: input.callId,
endedAtMs: Date.now(),
});
}የግል የገንዘብ ድጋፍ
የግል Kaigi መፍጠር ፣ መቀላቀል እና ማጠናቀቅ ሥራዎች ለግል የመግቢያ ነጥብ ክፍያ መከላከያ XOR ሊያስፈልጋቸው ይችላል ። መተግበሪያዎ ያንን ስህተት መያዝ አለበት እና እንደገና ከመሞከርዎ በፊት የራስ-መከላከያ እርምጃ መስጠት አለበት።
type PrivateKaigiFundingBridge = KaigiBridge & {
getPrivateKaigiConfidentialXorState(input: {
toriiUrl: string;
accountId: string;
}): Promise<{
shieldedBalance: string | null;
transparentBalance: string;
canSelfShield: boolean;
message?: string;
}>;
selfShieldPrivateKaigiXor(input: {
toriiUrl: string;
chainId: string;
accountId: string;
amount: string;
}): Promise<{ hash: string }>;
};
export async function selfShieldForPrivateKaigi(input: {
context: Omit<KaigiContext, "bridge"> & {
bridge: PrivateKaigiFundingBridge;
};
accountId: string;
amount: string;
}): Promise<void> {
const { bridge, toriiUrl, chainId } = input.context;
const state = await bridge.getPrivateKaigiConfidentialXorState({
toriiUrl,
accountId: input.accountId,
});
if (!state.canSelfShield) {
throw new Error(
state.message || "This account cannot self-shield XOR for private Kaigi.",
);
}
await bridge.selfShieldPrivateKaigiXor({
toriiUrl,
chainId,
accountId: input.accountId,
amount: input.amount,
});
}ማሳያ ውስጥ, UI ተጠቃሚው ራሱን ለመከላከል ይጠይቃል ከዚያም የመጀመሪያውን መፍጠር ወይም መቀላቀል እርምጃ እንደገና ይሞክራል.
የእጅ መውደቅ
አውቶማቲክ ምልክት በቀጥታ የኪስ ቦርሳ, Kaigi-ነክ Torii መስመሮች, እና የግል ሁነታ ውስጥ ማስረጃ ማመንጨት ላይ የተመሠረተ ነው. ለልማት እና ለተገደቡ አካባቢዎች በእጅ ወደ ኋላ ይያዙ:
CreateKaigiካልተሳካለት፣ አቅርቦቱን የያዘውን የእጅ ግብዣ አሳይ።JoinKaigiካልተሳካ አንድ ጥሬ መልስ ፓኬጅ ያሳዩ- አስተናጋጁ የምላሽ ጥቅሉን እንዲለጠፍ እና
setRemoteDescriptionን ይደውሉ ።
በእጅ ወደ ኋላ መመለስ WebRTC ለማስተካከል ጠቃሚ ነው ፣ ግን እንደ የቀጥታ Kaigi ፍሰት ተመሳሳይ የግል ሰንሰለት ላይ የምልክት ዋስትና አይሰጥም ።
የሙከራ ፍተሻ ዝርዝር
ለአንድነት ሙከራዎች ፣ ድልድዩን ይንቁ እና የእርስዎ UI የሚጠበቁትን Kaigi ጠቃሚ ጭነቶች የሚያልፍ መሆኑን ያረጋግጡ:
- አስተናጋጅ አካባቢያዊ ሚዲያዎችን ይፈጥራል እና
createKaigiMeetingያቀርባል - አስተናጋጅ
iroha://kaigi/join?call=...&secret=...ግብዣ ያሳያል - እንግዳው ግብዣውን ይመረምራል፣ ወደ
getKaigiCallይደውላል እንዲሁምjoinKaigiMeetingያቀርባል - ለምላሽ ምልክቶች አስተናጋጅ የሕዝብ አስተያየት መስጫዎች ወይም ሰዓቶች እና መልሱን ይተግብራል
- XOR በተከላከለበት ጊዜ ራስን ለመከላከል የግል ሁነታ ማሳሰቢያዎች ይጠፋሉ
- የቀጥታ ምልክት በማይገኝበት ጊዜ በእጅ ወደኋላ መመለስ ይታያል።
የተሟላ የማጣቀሻ የሙከራ ስብስብ ለማግኘት የዴሞ መተግበሪያው Kaigi እይታ እና ቅድመ ጭነት ድልድይ ሙከራዎችን ይመልከቱ:
npm test -- tests/kaigiView.spec.ts tests/preloadKaigiBridge.spec.ts
npm run e2e:uiየ UI ጭስ ሙከራው /kaigi መንገድ እንደሚሰራ ያረጋግጣል ። እውነተኛ ሚዲያ ሙከራ አሁንም ሁለት የገንዘብ ቦርሳዎች እና ሁለት መስኮቶች ወይም መሣሪያዎች ያስፈልገዋል ምክንያቱም የግብይት ፊርማ ፣ ካሜራ ፣ ማይክሮፎን እና WebRTC ፍቃዶች በሂደት ጊዜ ስለሚለያዩ።
በ TAIRA ላይ ምርመራ እያደረጉ ከሆነ እና ለጥሪው የተወሰነ መንገድ 404 የሚመለስ ከሆነ ፣ በመጀመሪያ አስተናጋጅ ቦርሳ በተሳካ ሁኔታ CreateKaigi እንደተላከ ያረጋግጡ ። ማንኛውም የተወሰነ ጥሪ ከመከሰቱ በፊት የስርጭት ጤና መጨረሻ ነጥቦች ሊገኙ ይችላሉ።
ቀጣይ እርምጃዎች
- በመተግበሪያዎ ውስጥ አስተማማኝ የክፍለ ጊዜ ቆይታ ሂሳብ ሲኖር
RecordKaigiUsageጋር የአጠቃቀም ቀረፃን ያክል። - በ
/v1/kaigi/relaysበኩል ሪሌዎችን በመመዝገብ እና በመከታተል የሪሌ ማሳያዎችን በሚጠቀሙበት ጊዜ። - በኦፕሬተር ዳሽቦርድዎ ውስጥ ያሉ የላይኛው
KaigiRosterSummary,KaigiUsageSummaryእናKaigiRelayHealthUpdatedክስተቶች።