Kako izgraditi privatne videokonzultacije u Next.js-u

Videokonzultacija izgleda kao jedan poziv, a u Next.js aplikaciji to je nekoliko značajki. Netko rezervira pola sata kod liječnice, odvjetnika, instruktorice ili savjetnika, i taj termin istodobno nestaje sa svih stranica, da ga nitko drugi ne rezervira. U dogovoreno vrijeme osoba koja je rezervirala čeka, a stručna osoba, na kojoj god stranici bila, vidi da čeka i pušta je unutra. Posjet je videopoziv tih dviju osoba kojem se nitko drugi ne može pridružiti i koji usluga koja ga prenosi ne može ni vidjeti ni čuti. Pokraj njega su poruke i datoteke termina, spremljene na vašem poslužitelju, a nakon njega bilješke stručne osobe.
Ovaj članak prolazi kroz svaki dio koji prava aplikacija treba, uz cijeli primjer koji radi: Consultations, web-stranicu za privatne konzultacije iz našeg vodiča za Next.js, na kojoj se rezerviraju stručne osobe, čeka u čekaonici i razgovara s njima na videu. Možete je isprobati uživo: budite Ava, čiji je posjet kod Lene upravo otvoren, i kliknite I'm ready. Zatim otvorite web-stranicu u privatnom prozoru kao Lena, pogledajte Avu u čekaonici i pustite Avu unutra.
Što videokonzultacija treba
- Rezervaciju koja vrijedi. Dostupne termine na svakoj stranici, i termin koji nestaje sa svih stranica čim ga netko rezervira.
- Čekaonicu. Osoba koja je rezervirala javlja da je spremna, a stručna osoba to vidi s bilo koje stranice, ne samo sa stranice posjeta.
- Puštanje unutra. Samo dvije osobe termina, samo oko njegova vremena, i osoba koja je rezervirala tek kad je stručna osoba pusti.
- Privatnost. Kameru i mikrofon šifrirane s kraja na kraj, tako da poslužitelji koji prenose poziv prosljeđuju ono što ne mogu ni vidjeti ni čuti.
- Poruke i datoteke pokraj posjeta, spremljene ondje gdje čuvate svoje podatke, i bilješke nakon njega.
- Kraj. Posjet se zatvara na kraju svojih pola sata, i nitko se u njega ne vraća.
Sve to možete izgraditi sami, na WebRTC-u, medijskim poslužiteljima i vlastitom websocket poslužitelju. Ili prepustite medije, čekaonicu i zaslon poziva oblaku u stvarnom vremenu, dok vaš poslužitelj zadržava ono što je doista vaše: rezervacije, pravila i datoteke. Upravo to radi Consultations, preko WordPlus Clouda.
Primjer: web-stranica za konzultacije
Stručne osobe nude polusatne termine: obiteljska liječnica, odvjetnik, instruktorica, savjetnik. Oni koji traže savjet rezerviraju termin ili odmah razgovaraju sa stručnom osobom koja je upravo dostupna. Svaki termin ima svoju stranicu: svoj posjet, svoje poruke i, kad posjet završi, bilješke stručne osobe. To je Next.js aplikacija s App Routerom, Better Authom i Postgresom, a njezin dio za rad u stvarnom vremenu stane u nekoliko datoteka. Pet koraka gradi njezine posjete.
1. Termini koji nestaju čim se rezerviraju
Rezervira se server actionom. Poslužitelj sprema rezervaciju, a polusatni termin koji je već zauzet odbija sama baza podataka. Zatim to javlja preko WordPlus Clouda, dvaput:
export async function bookVisit(expert: string, startsAt: number, topic: string): Promise<{ error: string }> {
const me = await currentUserId();
if (!me) return { error: 'Sign in first.' };
const booked = await book(me, expert, startsAt, topic);
if (typeof booked === 'string') return { error: booked };
await realtime.toUser(expert).emit('booked', { appointment: booked.id, name: booked.clientName, startsAt: booked.startsAt });
// Every page showing this expert's times takes this one away.
await realtime.to('experts').emit('changed');
redirect(`/appointments/${booked.id}`);
}toUser() stiže na svaku stranicu koju stručna osoba ima otvorenu, na bilo kojem uređaju, s obavijesti o novom posjetu. experts je soba kojoj se pridružuje svaka stranica prijavljenog korisnika i u kojoj govori samo poslužitelj. Svaka stranica čuje changed i ponovno traži sebe od svog poslužitelja, bez ponovnog učitavanja:
useRoom('experts', { changed: () => router.refresh() });Tko je gledao termine te stručne osobe, vidi kako pola sata nestaje. Ista soba javlja stranicama kad posjet počne ili završi, pa je i popis onih koji su upravo dostupni uvijek točan. WordPlus Cloud zna koji su posjeti u tijeku (realtime.listCalls()), a web-stranica za to ne vodi tablicu.
2. Čekaonica
Svaki termin ima čekaonicu, sobu prisutnosti nazvanu po njemu:
realtime.room('waiting:{id}', { presence: true }, async (user, { id }) => mayChat(user, id));U nju ulaze samo dvije osobe termina. Kad osoba koja je rezervirala klikne I'm ready, njezina se stranica pridružuje sobi i ostaje u njoj dok je stranica otvorena. Stranica stručne osobe čita tko je unutra:
function useWaiting(id: string, client: string): boolean {
return usePresence(`waiting:${id}`).some((member) => String(member.id) === client);
}Prisutnost prati stranicu: dovoljno je zatvoriti karticu da se izađe iz čekaonice. A stručna osoba ne mora biti na stranici posjeta. Poslužitelj to javlja događajem waiting preko realtime.toUser(), i na bilo kojoj stranici pojavljuje se obavijest „Ava is in the waiting room” koja otvara posjet.
3. Puštanje unutra
Posjet je grupni poziv nazvan po terminu, visit:81, deklariran jednom, po tom uzorku, sa svojim pravilom:
realtime.groupCalls('visit:{id}', async (user, { id }) => mayJoinVisit(user, id), { encrypt: true });export async function mayJoinVisit(user: string | number | null, id: string): Promise<boolean> {
const appointment = await appointmentOf(id);
if (!appointment || !isParty(appointment, user) || !visitOpen(appointment)) return false;
return String(user) === appointment.expert || appointment.admittedAt !== null;
}Dvije osobe termina i nitko drugi, dok je posjet otvoren: od deset minuta prije njegova vremena do kraja njegovih pola sata, osim ako je završio ranije. Stručna osoba ulazi kad god je posjet otvoren, a osoba koja je rezervirala tek nakon što je puštena. Puštanje unutra je server action koji označava termin i javlja to osobi koja je rezervirala:
export async function letIn(id: string): Promise<boolean> {
const me = await currentUserId();
const appointment = me ? await admit(id, me) : null;
if (!appointment) return false;
await realtime.toUser(appointment.client).emit('admitted', { appointment: id, name: appointment.expertName });
return true;
}Od tada pravilo kaže da, a stranica koja čeka sama ulazi u posjet. Kad se stranica želi pridružiti, najprije pita vlastiti poslužitelj web-stranice, na /api/realtime/calls: to je isti route handler kroz koji prolaze pozivi stranice za upoznavanje (kako implementirati videopozive u Next.js-u). Pravilo se izvodi sa sesijom web-stranice, a stranica dobiva propusnicu za posjet, potpisanu tajnom aplikacije, ili razlog zašto ne.
4. Posjet, šifriran s kraja na kraj
{ encrypt: true } u pravilu šifrira posjet s kraja na kraj. Svaki preglednik šifrira svoju kameru i mikrofon ključem koji stvara poslužitelj web-stranice i koji dobivaju samo oni koje pravilo pušta unutra. Ključevi ostaju na web-stranici i u dvama preglednicima, a medijski poslužitelji WordPlus Clouda prosljeđuju ono što ne mogu ni vidjeti ni čuti (kako rade medijski poslužitelji).
Posjet se prikazuje na samoj stranici termina, ondje gdje ga stranica postavi:
<CallSpot rt={rt} call={`visit:${id}`} join={join} joinWith="microphone camera" className="h-[32rem] rounded-2xl">
{/* The waiting room as each of the two sees it, until the page joins */}
</CallSpot>Prije posjeta CallSpot prikazuje ono što je u njemu: čekaonicu onako kako je vidi svaka od dviju osoba, s gumbom Let Ava in za stručnu osobu. join uvodi stranicu u posjet, čim stručna osoba pusti unutra ili čim osoba koja čeka bude puštena. joinWith="microphone camera" pri ulasku uključuje oboje, jer se na posjetu treba vidjeti i čuti od prvog trenutka. Na drugoj stranici aplikacije posjet se nastavlja u prozoru u kutu i vraća se ovamo kad se stranica termina ponovno otvori.
Posjet i završava. Stručna osoba ga završava gumbom, a web-stranica na kraju njegovih pola sata, mjeračem vremena koji postavlja kad posjet počne:
export async function endVisit(appointment: Appointment) {
await realtime.call(visitOf(appointment.id)).end().catch(() => {}); // not on, if nobody came in
await markEnded(appointment.id);
await realtime.toUser([appointment.expert, appointment.client]).emit('ended', { appointment: appointment.id });
await realtime.to('experts').emit('changed');
}end() izvodi obje osobe iz poziva, pravilo, vidjevši da je termin završio, više nikoga ne pušta unutra, a obje stranice kažu da je posjet završio.
5. Poruke i datoteke, a zatim bilješke
Svaki termin ima razgovor, sobu chat:{id}, samo za svoje dvije osobe, prije posjeta, tijekom njega i nakon njega. Gotovi Chat prikazuje ga pokraj posjeta, s prikazom tipkanja, potvrdama čitanja i datotekama:
<Chat
rt={useRealtime()}
room={room}
messages={`/api/messages?room=${room}`}
upload="/api/files"
accept="image/*,.pdf,.doc,.docx,.txt"
maxFileSize={10 * 1024 * 1024}
/>Fotografija, sken ili ugovor odlazi na vlastitu rutu web-stranice čim se odabere, a ruta pita pravilo sobe prije nego što ga spremi:
if (!me || !appointment || !(file instanceof File) || !(await realtime.mayJoin(room, me))) {
return Response.json({ error: 'This file is not for this conversation.' }, { status: 403 });
}Web-stranica sprema datoteku u vlastitu bazu podataka i otvara je samo tim dvjema osobama. WordPlus Cloud prenosi samo poruku koja kaže gdje se datoteka nalazi, zapečaćenu ključem koji drži web-stranica, a nikad samu datoteku. Web-stranica sprema i svaku poruku, iz webhooka message, pa razgovor ostaje dostupan objema osobama i nakon posjeta. Kad posjet završi, stručna osoba piše bilješke, web-stranica ih sprema, a stranica osobe koja je rezervirala odmah ih prikazuje, opet preko toUser().
Što dolazi uz to
- Razgovor odmah. Tko traži savjet, može zamoliti stručnu osobu koja je upravo dostupna za razgovor odmah. Njezina stranica prikazuje zahtjev, s minutom vremena da ga prihvati, i obje osobe ulaze ravno u novi posjet.
- Tko je dostupan, ažurno na svakoj stranici. Stručna osoba u posjetu prikazuje se kao zauzeta, prema
realtime.listCalls(), bez vaše tablice. - Na mreži ili ne. Čekaonica pokazuje je li stručna osoba već na mreži, s pomoću
useOnline(). - Imena i lica iz vaše aplikacije. Svaki prozorčić i svaka poruka prikazuju ime i fotografiju onako kako ih daje
profileweb-stranice, bez popisa korisnika spremljenog u WordPlus Cloudu.
Isprobajte, pa izgradite svoje
U demu uživo stručne osobe i oni koji traže savjet samo su vaši jedan dan, pa ono što ondje napišete ili s kim se nađete nitko drugi ne vidi, a posjet sam završava nakon 10 minuta. Ispod svake stranice How this page works korak po korak prikazuje kod koji je pokreće, s vrijednostima stranice koju imate otvorenu.
Vodič za privatne konzultacije izgrađuje cijelu web-stranicu, sa svakom datotekom njezina dijela za rad u stvarnom vremenu, Pozivi u Next.js-u pokazuju svaki način da poziv stavite u vlastitu aplikaciju, a Šifriranje objašnjava što je zapečaćeno i tko drži koji ključ. Za sastanak cijelog tima umjesto dviju osoba pročitajte kako implementirati videokonferencije u Next.js-u.
WordPlus Cloud for Apps ima cijenu prema istodobnim vezama, od 1.000 naviše, uz mjesečnu ili godišnju naplatu. Posjet je grupni poziv dviju osoba. S 1.000 veza grupni pozivi nisu obračunati do 32 osobe na videu istodobno, to jest 16 posjeta, pri čemu se osoba samo sa zvukom računa kao pola, a svakih daljnjih 1.000 veza dodaje još 12. Iznad toga svaka dodatna osoba na videu troši kredit po minuti, a pozivi između dviju osoba ne troše ništa. Pogledajte videopozive za aplikacije ili cijene za aplikacije. Pitanja o vašoj integraciji? Pišite nam.