Hooking Everything Up
Integrating Client and Server Components.
Finally, write the main
function where you'll connect to the gRPC server and call these functions:
func main() {
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.Dial("localhost:9090", opts...)
if err != nil {
log.Fatalf("error: %v", err)
}
defer conn.Close()
client := pb.NewTaskServiceClient(conn)
log.Printf("==== Calling CreateTask ====")
createTask(client, &pb.CreateTaskRequest{
Description: "Task 1",
UserId: "1",
Deadline: timestamppb.New(time.Now().AddDate(0, 0, 200)),
})
createTask(client, &pb.CreateTaskRequest{
Description: "Task 2",
UserId: "1",
Deadline: timestamppb.New(time.Now().AddDate(0, 0, 200)),
})
log.Printf("==== Calling GetTask ====")
getTask(client, &pb.GetTaskRequest{TaskId: createdTasks[0]})
log.Printf("==== Calling RecordTasks ====")
runRecordTasks(client)
log.Printf("==== Calling ListTasks ====")
listTasks(client, "1", time.Now().AddDate(0, 0, 100).Format(time.RFC3339))
log.Printf("==== Calling TaskChat ====")
runTaskChat(client)
}
Running the gRPC Client
Open the integrated terminal and start the server:
go run server/server.go
In another terminal, run the client:
go run client/client.go
You should see a similar output to the following:
2023/08/15 21:44:18 ==== Calling CreateTask ====
2023/08/15 21:44:18 Creating Task: { description: 'Task 1', user_id: '1', deadline: 'seconds:1709396058 nanos:668592939' }
2023/08/15 21:44:18 id:"43" description:"Task 1" user_id:"1" status:TASK_STATUS_INCOMPLETE deadline:{seconds:1709396058 nanos:668592939} created_at:{seconds:1692116058 nanos:669725049}
2023/08/15 21:44:18 Creating Task: { description: 'Task 2', user_id: '1', deadline: 'seconds:1709396058 nanos:675456659' }
2023/08/15 21:44:18 id:"44" description:"Task 2" user_id:"1" status:TASK_STATUS_INCOMPLETE deadline:{seconds:1709396058 nanos:675456659} created_at:{seconds:1692116058 nanos:675535350}
2023/08/15 21:44:18 ==== Calling GetTask ====
2023/08/15 21:44:18 id:"43" description:"Task 1" user_id:"1" status:TASK_STATUS_INCOMPLETE deadline:{seconds:1709396058 nanos:668593000} created_at:{seconds:1692116058 nanos:669725000}
2023/08/15 21:44:18 ==== Calling RecordTasks ====
2023/08/15 21:44:18 Recording 8 tasks
2023/08/15 21:44:18 Tasks summary: 8 tasks created
2023/08/15 21:44:18 ==== Calling ListTasks ====
2023/08/15 21:44:18 Listing all tasks of User 1 with deadline within 2023-11-23T21:44:18+05:30
2023/08/15 21:44:18 Task: { Id: 45, Description: 'Task 0', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-08-24T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 46, Description: 'Task 1', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-09-11T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 47, Description: 'Task 2', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-10-23T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 48, Description: 'Task 3', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-11-15T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 49, Description: 'Task 4', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-10-08T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 50, Description: 'Task 5', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-09-22T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 51, Description: 'Task 6', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-10-17T16:14:18Z' }
2023/08/15 21:44:18 Task: { Id: 52, Description: 'Task 7', Status: 'TASK_STATUS_INCOMPLETE', Deadline: '2023-10-23T16:14:18Z' }
2023/08/15 21:44:18 ==== Calling TaskChat ====
2023/08/15 21:44:18 Got comment at task 43 by user 1
2023/08/15 21:44:18 Got comment at task 43 by user 2
2023/08/15 21:44:18 Got comment at task 43 by user 1
2023/08/15 21:44:18 Got comment at task 43 by user 1
2023/08/15 21:44:18 Got comment at task 43 by user 3
2023/08/15 21:44:18 Got comment at task 43 by user 2
2023/08/15 21:44:18 Got comment at task 43 by user 3
Congratulations—the gRPC server and client are both working correctly. Here's the code of client.go
in all its glory:
package main
import (
"context"
pb "go-grpc-demo/src/go"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/types/known/timestamppb"
"io"
"log"
"math/rand"
"strconv"
"time"
)
var createdTasks []string
func createTask(client pb.TaskServiceClient, createTaskRequest *pb.CreateTaskRequest) {
log.Printf("Creating Task: { description: '%s', user_id: '%s', deadline: '%s' }", createTaskRequest.Description, createTaskRequest.UserId, createTaskRequest.Deadline)
createdTask, err := client.CreateTask(context.Background(), createTaskRequest)
if err == nil {
log.Println(createdTask)
createdTasks = append(createdTasks, createdTask.Id)
}
}
func getTask(client pb.TaskServiceClient, geTaskRequest *pb.GetTaskRequest) {
task, err := client.GetTask(context.Background(), geTaskRequest)
if err == nil {
log.Println(task)
}
}
func runRecordTasks(client pb.TaskServiceClient) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
tasksCount := int(r.Int31n(10)) + 2
var createTaskRequests []*pb.CreateTaskRequest
for i := 0; i < tasksCount; i++ {
deadlineDaysAfter := int(r.Int31n(100))
createTaskRequests = append(createTaskRequests, &pb.CreateTaskRequest{
Description: "Task " + strconv.Itoa(i),
UserId: "1",
Deadline: timestamppb.New(time.Now().AddDate(0, 0, deadlineDaysAfter)),
})
}
log.Printf("Recording %d tasks", tasksCount)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := client.RecordTasks(ctx)
if err != nil {
log.Fatalf("error %v", err)
}
for _, createTaskRequest := range createTaskRequests {
if err := stream.Send(createTaskRequest); err != nil {
log.Fatalf("stream.Send(%v) failed: %v", createTaskRequest, err)
}
}
reply, err := stream.CloseAndRecv()
if err != nil {
log.Fatalf("error %v", err)
}
log.Printf("Tasks summary: %s tasks created", reply.NoOfTasksCreated)
}
func listTasks(client pb.TaskServiceClient, userId string, deadline string) {
log.Printf("Listing all tasks of User %s with deadline within %s", userId, deadline)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
deadlineTime, err := time.Parse(time.RFC3339, deadline)
if err != nil {
log.Fatalf("error parsing time: %v", err)
}
stream, err := client.ListTasks(ctx, &pb.ListTasksRequest{
UserId: userId,
Deadline: timestamppb.New(deadlineTime),
})
for {
task, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("error %v", err)
}
log.Printf(
"Task: { Id: %s, Description: '%s', Status: '%s', Deadline: '%s' }",
task.Id, task.Description, task.Status, task.Deadline.AsTime().Format(time.RFC3339))
}
}
func runTaskChat(client pb.TaskServiceClient) {
comments := []*pb.TaskComment{
{UserId: "1", TaskId: createdTasks[0], Comment: "Comment 1", CreatedAt: timestamppb.Now()},
{UserId: "2", TaskId: createdTasks[0], Comment: "Comment 2", CreatedAt: timestamppb.Now()},
{UserId: "1", TaskId: createdTasks[0], Comment: "Comment 3", CreatedAt: timestamppb.Now()},
{UserId: "1", TaskId: createdTasks[0], Comment: "Comment 4", CreatedAt: timestamppb.Now()},
{UserId: "3", TaskId: createdTasks[0], Comment: "Comment 5", CreatedAt: timestamppb.Now()},
{UserId: "2", TaskId: createdTasks[0], Comment: "Comment 6", CreatedAt: timestamppb.Now()},
{UserId: "3", TaskId: createdTasks[0], Comment: "Comment 7", CreatedAt: timestamppb.Now()},
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := client.TaskChat(ctx)
if err != nil {
log.Fatalf("error: %v", err)
}
wc := make(chan struct{})
go func() {
for {
in, err := stream.Recv()
if err == io.EOF {
close(wc)
return
}
if err != nil {
log.Fatalf("error: %v", err)
}
log.Printf("Got comment at task %s by user %s", in.TaskId, in.UserId)
}
}()
for _, comment := range comments {
if err := stream.Send(comment); err != nil {
log.Fatalf("Send failed %v", err)
}
}
stream.CloseSend()
<-wc
}
func main() {
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.Dial("localhost:9090", opts...)
if err != nil {
log.Fatalf("error: %v", err)
}
defer conn.Close()
client := pb.NewTaskServiceClient(conn)
log.Printf("==== Calling CreateTask ====")
createTask(client, &pb.CreateTaskRequest{
Description: "Task 1",
UserId: "1",
Deadline: timestamppb.New(time.Now().AddDate(0, 0, 200)),
})
createTask(client, &pb.CreateTaskRequest{
Description: "Task 2",
UserId: "1",
Deadline: timestamppb.New(time.Now().AddDate(0, 0, 200)),
})
log.Printf("==== Calling GetTask ====")
getTask(client, &pb.GetTaskRequest{TaskId: createdTasks[0]})
log.Printf("==== Calling RecordTasks ====")
runRecordTasks(client)
log.Printf("==== Calling ListTasks ====")
listTasks(client, "1", time.Now().AddDate(0, 0, 100).Format(time.RFC3339))
log.Printf("==== Calling TaskChat ====")
runTaskChat(client)
}