docs: refine gRPC guide section numbers and add CloseAndRecv & fileStore explanations
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
package modular
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"grpccanary/lib/grpc/modular/protoapi"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
func AskingDateTime(ctx context.Context, m protoapi.CoreServiceClient) (*protoapi.DateTime, error) {
|
||||
request := &protoapi.RequestDateTime{
|
||||
Value: "Please send me the date and time",
|
||||
}
|
||||
return m.GetDate(ctx, request)
|
||||
}
|
||||
|
||||
func AskPass(ctx context.Context, m protoapi.CoreServiceClient, seed int64, length int64) (*protoapi.RandomPass, error) {
|
||||
request := &protoapi.RequestPass{
|
||||
Seed: seed,
|
||||
Length: length,
|
||||
}
|
||||
return m.GetRandomPass(ctx, request)
|
||||
}
|
||||
|
||||
func AskUpdateSensingData(ctx context.Context, m protoapi.CoreServiceClient, deviceId string, temp float64, humid float64) (*protoapi.SensingResponse, error) {
|
||||
request := &protoapi.SensingData{
|
||||
DeviceId: deviceId,
|
||||
Temperature: temp,
|
||||
Humidity: humid,
|
||||
}
|
||||
return m.UpdateSensingData(ctx, request)
|
||||
}
|
||||
|
||||
func AskUploadFile(ctx context.Context, m protoapi.FileTransferServiceClient, fileName string, fileData []byte) (*protoapi.UploadStatus, error) {
|
||||
stream, err := m.UploadFile(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chunkSize := 1024
|
||||
totalBytes := len(fileData)
|
||||
|
||||
for i := 0; i < totalBytes; i += chunkSize {
|
||||
end := i + chunkSize
|
||||
if end > totalBytes {
|
||||
end = totalBytes
|
||||
}
|
||||
|
||||
err := stream.Send(&protoapi.FileChunk{
|
||||
FileName: fileName,
|
||||
Content: fileData[i:end],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return stream.CloseAndRecv()
|
||||
}
|
||||
|
||||
func AskListFiles(ctx context.Context, m protoapi.FileTransferServiceClient) (*protoapi.FileList, error) {
|
||||
return m.ListFiles(ctx, &protoapi.EmptyRequest{})
|
||||
}
|
||||
|
||||
func AskDownloadFile(ctx context.Context, m protoapi.FileTransferServiceClient, fileName string) ([]byte, error) {
|
||||
stream, err := m.DownloadFile(ctx, &protoapi.DownloadRequest{FileName: fileName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buffer []byte
|
||||
for {
|
||||
chunk, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer = append(buffer, chunk.GetContent()...)
|
||||
}
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
func AskSubscribeAlerts(ctx context.Context, m protoapi.AlertServiceClient, clientId string, topic string) {
|
||||
stream, err := m.SubscribeAlerts(ctx, &protoapi.AlertSubscription{
|
||||
ClientId: clientId,
|
||||
Topic: topic,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] Failed to subscribe alerts:", err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
alert, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
fmt.Println("[Modular Client] Alert subscription stream closed by server.")
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fmt.Printf("\n🔔 [Modular ALERT RECEIVED] ID: %s | Device: %s | Msg: %s | Time: %s\n\n",
|
||||
alert.GetAlertId(), alert.GetDeviceId(), alert.GetMessage(),
|
||||
time.Unix(alert.GetTimestamp(), 0).Format("15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
func ClientRun(addr string) {
|
||||
conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] NewClient error:", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
coreClient := protoapi.NewCoreServiceClient(conn)
|
||||
fileClient := protoapi.NewFileTransferServiceClient(conn)
|
||||
alertClient := protoapi.NewAlertServiceClient(conn)
|
||||
|
||||
// Background Subscription
|
||||
alertCtx, alertCancel := context.WithCancel(context.Background())
|
||||
defer alertCancel()
|
||||
go AskSubscribeAlerts(alertCtx, alertClient, "modular-client-01", "temperature_warnings")
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
r, err := AskingDateTime(context.Background(), coreClient)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] GetDate error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("[Modular Client] Server Date and Time:", r.Value)
|
||||
|
||||
length := int64(rand.Intn(20))
|
||||
p, err := AskPass(context.Background(), coreClient, 100, length+1)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] GetRandomPass error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("[Modular Client] Random Password:", p.Password)
|
||||
|
||||
res, err := AskUpdateSensingData(context.Background(), coreClient, "modular-sensor-01", 24.5, 52.3)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] UpdateSensingData error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("[Modular Client] Sensing Update Success:", res.Success)
|
||||
|
||||
// File Upload
|
||||
dummyData := make([]byte, 10240)
|
||||
for i := range dummyData {
|
||||
dummyData[i] = byte(rand.Intn(256))
|
||||
}
|
||||
fmt.Println("[Modular Client] Uploading dummy file...")
|
||||
status, err := AskUploadFile(context.Background(), fileClient, "firmware_modular.bin", dummyData)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] File upload failed:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("[Modular Client] Upload Success:", status.Success)
|
||||
|
||||
// File List
|
||||
list, err := AskListFiles(context.Background(), fileClient)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] ListFiles failed:", err)
|
||||
return
|
||||
}
|
||||
for i, f := range list.GetFiles() {
|
||||
fmt.Printf("[Modular Client] File [%d]: %s, size: %d\n", i+1, f.GetFileName(), f.GetFileSize())
|
||||
}
|
||||
|
||||
// File Download & Verification
|
||||
downloadedData, err := AskDownloadFile(context.Background(), fileClient, "firmware_modular.bin")
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] Download failed:", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("[Modular Client] Downloaded %d bytes.\n", len(downloadedData))
|
||||
|
||||
isMatch := true
|
||||
if len(dummyData) != len(downloadedData) {
|
||||
isMatch = false
|
||||
} else {
|
||||
for i := range dummyData {
|
||||
if dummyData[i] != downloadedData[i] {
|
||||
isMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("[Modular Client] Data Integrity Checked: %t\n", isMatch)
|
||||
|
||||
// Trigger alert
|
||||
fmt.Println("[Modular Client] Triggering abnormal high-temperature...")
|
||||
_, err = AskUpdateSensingData(context.Background(), coreClient, "modular-sensor-01", 45.8, 60.1)
|
||||
if err != nil {
|
||||
fmt.Println("[Modular Client] UpdateSensingData (abnormal) error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
Reference in New Issue
Block a user