Skip to content

Commit 0e18036

Browse files
committed
feat(rpc): add example
1 parent 8420d48 commit 0e18036

File tree

1 file changed

+320
-0
lines changed

1 file changed

+320
-0
lines changed

examples/rpc/main.go

+320
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"math"
8+
"time"
9+
10+
"github.com/google/uuid"
11+
"github.com/livekit/protocol/logger"
12+
lksdk "github.com/livekit/server-sdk-go/v2"
13+
)
14+
15+
const (
16+
caller = "caller"
17+
greeter = "greeter"
18+
mathGenius = "math-genius"
19+
)
20+
21+
var (
22+
host, apiKey, apiSecret string
23+
)
24+
25+
func init() {
26+
flag.StringVar(&host, "host", "", "livekit server host")
27+
flag.StringVar(&apiKey, "api-key", "", "livekit api key")
28+
flag.StringVar(&apiSecret, "api-secret", "", "livekit api secret")
29+
}
30+
31+
func performGreeting(room *lksdk.Room) {
32+
logger.Infow("[Caller] Letting the greeter know that I've arrived")
33+
res, err := room.LocalParticipant.PerformRpc(lksdk.PerformRpcParams{
34+
DestinationIdentity: "greeter",
35+
Method: "arrival",
36+
Payload: "Hello",
37+
ResponseTimeout: 10000 * time.Millisecond,
38+
})
39+
40+
if err != nil {
41+
logger.Errorw("[Caller] RPC call failed: ", err)
42+
return
43+
}
44+
45+
logger.Infow(fmt.Sprintf("[Caller] That's nice, the greeter said: %s", *res))
46+
}
47+
48+
func performDisconnection(room *lksdk.Room) {
49+
logger.Infow("[Caller] Checking back in on the greeter...")
50+
res, err := room.LocalParticipant.PerformRpc(lksdk.PerformRpcParams{
51+
DestinationIdentity: "greeter",
52+
Method: "arrival",
53+
Payload: "You still there?",
54+
ResponseTimeout: 10000 * time.Millisecond,
55+
})
56+
57+
if err != nil {
58+
if err.(*lksdk.RpcError).Code == lksdk.RpcRecipientDisconnected {
59+
logger.Infow("[Caller] The greeter disconnected during the request.")
60+
} else {
61+
logger.Errorw("[Caller] Unexpected error: ", err)
62+
}
63+
return
64+
}
65+
66+
logger.Infow(fmt.Sprintf("[Caller] That's nice, the greeter said: %s", *res))
67+
}
68+
69+
func performSquareRoot(room *lksdk.Room) {
70+
logger.Infow("[Caller] What's the square root of 16?")
71+
72+
number := 16
73+
payload, err := json.Marshal(number)
74+
if err != nil {
75+
logger.Errorw("Failed to marshal square root request", err)
76+
return
77+
}
78+
79+
res, err := room.LocalParticipant.PerformRpc(lksdk.PerformRpcParams{
80+
DestinationIdentity: "math-genius",
81+
Method: "square-root",
82+
Payload: string(payload),
83+
ResponseTimeout: 10000 * time.Millisecond,
84+
})
85+
86+
if err != nil {
87+
logger.Errorw("[Caller] RPC call failed:", err)
88+
return
89+
}
90+
91+
var result float64
92+
err = json.Unmarshal([]byte(*res), &result)
93+
if err != nil {
94+
logger.Errorw("Failed to unmarshal square root result", err)
95+
return
96+
}
97+
logger.Infow(fmt.Sprintf("[Caller] Nice, the answer was: %v", result))
98+
}
99+
100+
func performQuantumHypergeometricSeries(room *lksdk.Room) {
101+
logger.Infow("[Caller] What's the quantum hypergeometric series of 42?")
102+
103+
number := 42
104+
payload, err := json.Marshal(number)
105+
if err != nil {
106+
logger.Errorw("Failed to marshal quantum hypergeometric series request", err)
107+
return
108+
}
109+
110+
res, err := room.LocalParticipant.PerformRpc(lksdk.PerformRpcParams{
111+
DestinationIdentity: "math-genius",
112+
Method: "quantum-hypergeometric-series",
113+
Payload: string(payload),
114+
ResponseTimeout: 10000 * time.Millisecond,
115+
})
116+
117+
if err != nil {
118+
if err.(*lksdk.RpcError).Code == lksdk.RpcUnsupportedMethod {
119+
logger.Infow("[Caller] Aww looks like the genius doesn't know that one.")
120+
} else {
121+
logger.Errorw("[Caller] Unexpected error:", err)
122+
}
123+
return
124+
}
125+
126+
var result float64
127+
err = json.Unmarshal([]byte(*res), &result)
128+
if err != nil {
129+
logger.Errorw("Failed to unmarshal quantum hypergeometric series result", err)
130+
return
131+
}
132+
133+
logger.Infow(fmt.Sprintf("[Caller] genius says %v!", result))
134+
}
135+
136+
func performDivide(room *lksdk.Room) {
137+
logger.Infow("[Caller] Let's try dividing 10 by 0")
138+
139+
numerator := 10
140+
denominator := 0
141+
142+
payload, err := json.Marshal(struct {
143+
Numerator float64 `json:"numerator"`
144+
Denominator float64 `json:"denominator"`
145+
}{
146+
Numerator: float64(numerator),
147+
Denominator: float64(denominator),
148+
})
149+
if err != nil {
150+
logger.Errorw("Failed to marshal divide request", err)
151+
return
152+
}
153+
154+
res, err := room.LocalParticipant.PerformRpc(lksdk.PerformRpcParams{
155+
DestinationIdentity: "math-genius",
156+
Method: "divide",
157+
Payload: string(payload),
158+
ResponseTimeout: 10000 * time.Millisecond,
159+
})
160+
161+
if err != nil {
162+
if rpcErr, ok := err.(*lksdk.RpcError); ok {
163+
if rpcErr.Code == lksdk.RpcApplicationError {
164+
logger.Infow("[Caller] Oops! I guess that didn't work. Let's try something else.")
165+
} else {
166+
logger.Errorw(fmt.Sprintf("[Caller] Unexpected RPC error: %s", rpcErr.Error()), nil)
167+
}
168+
} else {
169+
logger.Errorw("[Caller] Unexpected error:", err)
170+
}
171+
return
172+
}
173+
174+
var result float64
175+
err = json.Unmarshal([]byte(*res), &result)
176+
if err != nil {
177+
logger.Errorw("Failed to unmarshal divide result", err)
178+
return
179+
}
180+
181+
logger.Infow(fmt.Sprintf("[Caller] The result is %v", result))
182+
}
183+
184+
func registerReceiverMethods(rooms map[string]*lksdk.Room) {
185+
greeterRoom := rooms[greeter]
186+
mathGeniusRoom := rooms[mathGenius]
187+
188+
arrivalHandler := func(data lksdk.RpcInvocationData) (string, error) {
189+
resultChan := make(chan string)
190+
191+
logger.Infow(fmt.Sprintf("[Greeter] Oh %s arrived and said %s", data.CallerIdentity, data.Payload))
192+
193+
time.AfterFunc(2000*time.Millisecond, func() {
194+
resultChan <- "Welcome and have a wonderful day!"
195+
})
196+
197+
return <-resultChan, nil
198+
}
199+
greeterRoom.RegisterRpcMethod("arrival", arrivalHandler)
200+
201+
squareRootHandler := func(data lksdk.RpcInvocationData) (string, error) {
202+
resultChan := make(chan string)
203+
var number float64
204+
err := json.Unmarshal([]byte(data.Payload), &number)
205+
if err != nil {
206+
logger.Errorw("Failed to unmarshal square root request", err)
207+
return "", err
208+
}
209+
210+
logger.Infow(fmt.Sprintf("[Math Genius] I guess %s wants the square root of %s. I've only got %v seconds to respond but I think I can pull it off ", data.CallerIdentity, data.Payload, data.ResponseTimeout.Seconds()))
211+
logger.Infow("[Math Genius] *doing math*...")
212+
213+
time.AfterFunc(2000*time.Millisecond, func() {
214+
result := math.Sqrt(number)
215+
logger.Infow(fmt.Sprintf("[MathGenius] Aha! It's %v", result))
216+
217+
jsonBytes, err := json.Marshal(result)
218+
if err != nil {
219+
logger.Errorw("Failed to marshal square root result", err)
220+
return
221+
}
222+
223+
resultChan <- string(jsonBytes)
224+
})
225+
226+
return <-resultChan, nil
227+
}
228+
mathGeniusRoom.RegisterRpcMethod("square-root", squareRootHandler)
229+
230+
divideHandler := func(data lksdk.RpcInvocationData) (string, error) {
231+
resultChan := make(chan string)
232+
233+
type DivideRequest struct {
234+
Numerator float64 `json:"numerator"`
235+
Denominator float64 `json:"denominator"`
236+
}
237+
var payload DivideRequest
238+
err := json.Unmarshal([]byte(data.Payload), &payload)
239+
if err != nil {
240+
logger.Errorw("Failed to unmarshal divide request", err)
241+
return "", err
242+
}
243+
244+
logger.Infow(fmt.Sprintf("[Math Genius] %s wants to divide %v by %v. Let me think...", data.CallerIdentity, payload.Numerator, payload.Denominator))
245+
246+
if payload.Denominator == 0 {
247+
return "", fmt.Errorf("cannot divide by zero")
248+
}
249+
250+
time.AfterFunc(2000*time.Millisecond, func() {
251+
result := payload.Numerator / payload.Denominator
252+
logger.Infow(fmt.Sprintf("[MathGenius] %v / %v = %v", payload.Numerator, payload.Denominator, result))
253+
254+
jsonBytes, err := json.Marshal(result)
255+
if err != nil {
256+
logger.Errorw("Failed to marshal divide result", err)
257+
return
258+
}
259+
260+
resultChan <- string(jsonBytes)
261+
})
262+
263+
return <-resultChan, nil
264+
}
265+
mathGeniusRoom.RegisterRpcMethod("divide", divideHandler)
266+
}
267+
268+
func main() {
269+
logger.InitFromConfig(&logger.Config{Level: "info"}, "rpc-demo")
270+
lksdk.SetLogger(logger.GetLogger())
271+
flag.Parse()
272+
273+
roomName := "rpc-demo" + uuid.New().String()[:8]
274+
logger.Infow("connecting participants to room", "roomName", roomName)
275+
276+
participants := []string{caller, greeter, mathGenius}
277+
278+
rooms := map[string]*lksdk.Room{}
279+
for _, p := range participants {
280+
room, err := lksdk.ConnectToRoom(host, lksdk.ConnectInfo{
281+
APIKey: apiKey,
282+
APISecret: apiSecret,
283+
RoomName: roomName,
284+
ParticipantIdentity: p,
285+
}, nil)
286+
if err != nil {
287+
logger.Errorw("failed to connect to room", err, "participant", p)
288+
return
289+
}
290+
rooms[p] = room
291+
}
292+
defer func() {
293+
for _, room := range rooms {
294+
room.Disconnect()
295+
}
296+
logger.Infow("Participants disconnected. Example completed.")
297+
}()
298+
299+
registerReceiverMethods(rooms)
300+
301+
logger.Infow("participants connected to room, starting rpc demo", "roomName", roomName)
302+
303+
logger.Infow("Running greeting example...")
304+
performGreeting(rooms[caller])
305+
306+
logger.Infow("Running error handling example...")
307+
performDivide(rooms[caller])
308+
309+
logger.Infow("Running math example...")
310+
performSquareRoot(rooms[caller])
311+
time.Sleep(2000 * time.Millisecond)
312+
performQuantumHypergeometricSeries(rooms[caller])
313+
314+
logger.Infow("Running disconnection example...")
315+
rooms[greeter].Disconnect()
316+
time.Sleep(1000 * time.Millisecond)
317+
performDisconnection(rooms[caller])
318+
319+
logger.Infow("participants done, disconnecting")
320+
}

0 commit comments

Comments
 (0)