refactor: replace GetRandom with IoT sensing data update scenario
This commit is contained in:
@@ -13,3 +13,6 @@ update.sh
|
||||
|
||||
# Workspace-specific scripts
|
||||
/resume_all.sh
|
||||
|
||||
# Local downloaded binary tools
|
||||
/bin/
|
||||
|
||||
@@ -89,8 +89,9 @@ Serving requests...
|
||||
Client:
|
||||
Server Date and Time: 2026-07-12 20:00:00.123456789 +0900 KST m=+1.000000001
|
||||
Random Password: &c(D7f/G#s%d
|
||||
Random Integer 1: 42
|
||||
Random Integer 2: 87
|
||||
Received sensing data - Device: sensor-room-01, Temp: 24.50°C, Humid: 52.30%
|
||||
Sensing Update Success: true
|
||||
Sensing Update Message: Sensing data updated successfully for device sensor-room-01
|
||||
```
|
||||
|
||||
### 4. 트러블슈팅
|
||||
|
||||
+26
-24
@@ -28,19 +28,19 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격
|
||||
|
||||
---
|
||||
|
||||
## 2. 실습 프로젝트 소개: Random 데이터 서비스
|
||||
## 2. 실습 프로젝트 소개: IoT 센싱 데이터 수집 서비스
|
||||
|
||||
본 튜토리얼에서는 gRPC 분산 통신 기법을 실증적으로 학습하기 위해 가상의 **Random 데이터 API 서비스** 프로젝트를 직접 설계하고 구현해 나갑니다.
|
||||
본 튜토리얼에서는 gRPC 분산 통신 기법을 실증적으로 학습하기 위해 현업에서 가장 범용적으로 쓰이는 가상의 **IoT 센싱 데이터 수집 및 기기 관리 서비스** 프로젝트를 직접 설계하고 구현해 나갑니다.
|
||||
|
||||
### 2.1 프로젝트 시나리오
|
||||
사물인터넷(IoT) 센서 노드나 지능형 멀티 에이전트 분산 환경에서는 기기들이 중앙 서버에 접속해 상태 정보(날짜/시간)를 동기화하거나, 보안 패킷 전송을 위해 임시 원격 패스워드를 발급받고, 연산용 고유 난수를 안전하게 질의해야 하는 현실적인 통신 요건이 존재합니다.
|
||||
우리가 개발할 `Random` 서비스는 이에 대응하는 다음 3가지 원격 프로시저(RPC)를 구현합니다:
|
||||
1. **서버 시간 및 날짜 조회 (`GetDate`)**: 클라이언트가 요청 시 서버는 내부 시스템의 포맷팅된 시간 문자열을 가공하여 반환합니다.
|
||||
2. **일회성 보안 패스워드 발급 (`GetRandomPass`)**: 클라이언트가 난수 시드와 바이트 길이를 명시하여 요청하면, 서버는 안전한 ASCII 비밀번호 문자열을 조립해 응답합니다.
|
||||
3. **의사 난수 정수 생성 (`GetRandom`)**: 재현성을 위해 시드값과 시퀀스 위치를 인자로 전달받아 계산에 부합하는 정수 난수값을 연산해 반환합니다.
|
||||
사물인터넷(IoT) 센서 노드나 분산 멀티 에이전트 환경에서는 엣지 기기들이 중앙 서버에 접속해 통신 가능 여부를 검증하고 상태 정보(날짜/시간)를 수집하거나, 임시 보안 인증을 위한 비밀번호 발급을 요청하고, 실시간으로 센싱한 환경 정보(온도, 습도 등)를 지속적으로 업데이트해야 하는 현실적인 시나리오가 요구됩니다.
|
||||
우리가 개발할 `IoTService`는 이에 대응하는 다음 3가지 핵심 원격 프로시저(RPC)를 수행합니다:
|
||||
1. **서버 시간 및 날짜 조회 (`GetDate`)**: 기기가 접속 상태를 확인하며 동기화를 위해 서버의 현재 날짜와 시간 포맷 문자열을 반환받습니다.
|
||||
2. **센싱 데이터 업데이트 (`UpdateSensingData`)**: 센서 노드가 주기적으로 수집한 물리 데이터(온도, 습도) 및 기기 식별자(Device ID)를 전달하면, 서버는 데이터 정합성을 검증한 후 성공 여부를 반환합니다.
|
||||
3. **일회성 보안 패스워드 발급 (`GetRandomPass`)**: 기기가 임시 통신 세션 수립을 위해 난수 생성 시드와 보안 문자열 길이를 전달하면, 무작위 ASCII 임시 패스워드를 연산하여 응답받습니다.
|
||||
|
||||
### 2.2 학습 목표 및 진행 방법
|
||||
이 간단하면서도 긴밀한 데이터 파이프라인을 구축하는 실습을 통해 학습자는 다음 gRPC 지식 체계를 단계별로 마스터하게 됩니다:
|
||||
이 유기적인 IoT 데이터 통신 모듈을 구축하는 실습을 통해 학습자는 다음 gRPC 지식 체계를 단계별로 마스터하게 됩니다:
|
||||
* **스키마 설계**: `.proto` IDL 문법을 활용해 데이터 형식(Message)과 원격 함수(Service RPC) 계약을 강제하는 법을 습득합니다.
|
||||
* **Stub 컴파일**: `protoc` 도구 체인을 가동하여 Go 프로그래밍 언어 소스코드를 안전하게 생성하고 프로젝트 빌드에 바인딩하는 기법을 배웁니다.
|
||||
* **네트워크 구현**: 실제로 TCP 소켓을 확보하여 gRPC 서버를 실행하고, 클라이언트가 평문 커넥션을 수립하여 실시간 동기식 원격 프로시저를 직접 기동하는 엔드투엔드 구동 구조를 체득합니다.
|
||||
@@ -49,26 +49,28 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격
|
||||
|
||||
## 3. 인터페이스 명세서 (`protoapi.proto`)
|
||||
|
||||
저장소 루트의 [protoapi.proto](../protoapi.proto) 파일은 앞서 설계한 `Random` 서비스를 구축하기 위해 아래와 같이 사양을 선언해 둡니다.
|
||||
저장소 루트의 [protoapi.proto](../protoapi.proto) 파일은 앞서 설계한 `IoTService`를 구축하기 위해 아래와 같이 사양을 선언해 둡니다.
|
||||
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "./protoapi/;protoapi";
|
||||
|
||||
service Random {
|
||||
service IoTService {
|
||||
rpc GetDate (RequestDateTime) returns (DateTime);
|
||||
rpc GetRandom (RandomParams) returns (RandomInt);
|
||||
rpc UpdateSensingData (SensingData) returns (SensingResponse);
|
||||
rpc GetRandomPass (RequestPass) returns (RandomPass);
|
||||
}
|
||||
|
||||
message RandomParams {
|
||||
int64 Seed = 1;
|
||||
int64 Place = 2;
|
||||
message SensingData {
|
||||
string DeviceId = 1;
|
||||
double Temperature = 2;
|
||||
double Humidity = 3;
|
||||
}
|
||||
|
||||
message RandomInt {
|
||||
int64 Value = 1;
|
||||
message SensingResponse {
|
||||
bool Success = 1;
|
||||
string Message = 2;
|
||||
}
|
||||
|
||||
message DateTime {
|
||||
@@ -124,16 +126,16 @@ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
||||
|
||||
* **구조체 정의**:
|
||||
```go
|
||||
type RandomServer struct {
|
||||
protoapi.UnimplementedRandomServer
|
||||
type IoTServer struct {
|
||||
protoapi.UnimplementedIoTServiceServer
|
||||
}
|
||||
```
|
||||
`UnimplementedRandomServer`를 임베딩하여, 향후 메서드가 새로 추가되더라도 기존 서버가 빌드 에러 없이 최소한의 호환(unimplemented 에러 응답)을 가지게 강제합니다.
|
||||
`UnimplementedIoTServiceServer`를 임베딩하여, 향후 메서드가 새로 추가되더라도 기존 서버가 빌드 에러 없이 최소한의 호환(unimplemented 에러 응답)을 가지게 강제합니다.
|
||||
* **서버 기동 흐름**:
|
||||
```go
|
||||
server := grpc.NewServer()
|
||||
var randomServer RandomServer
|
||||
protoapi.RegisterRandomServer(server, randomServer)
|
||||
var iotServer IoTServer
|
||||
protoapi.RegisterIoTServiceServer(server, iotServer)
|
||||
reflection.Register(server) // grpcurl 등 외부 디버깅 목적
|
||||
listen, _ := net.Listen("tcp", port)
|
||||
server.Serve(listen)
|
||||
@@ -145,17 +147,17 @@ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
||||
```go
|
||||
conn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
defer conn.Close()
|
||||
client := protoapi.NewRandomClient(conn)
|
||||
client := protoapi.NewIoTServiceClient(conn)
|
||||
```
|
||||
`insecure.NewCredentials()`를 전달하여 TLS를 건너뛴 채 평문으로 빠르고 간단한 로컬 테스트 환경을 구축합니다.
|
||||
* **원격 호출**:
|
||||
`client.GetDate()`, `client.GetRandom()`, `client.GetRandomPass()`를 차례로 호출하여 매개변수와 결과를 콘솔로 확인합니다.
|
||||
`client.GetDate()`, `client.GetRandomPass()`, `client.UpdateSensingData()`를 차례로 호출하여 매개변수와 결과를 콘솔로 확인합니다.
|
||||
|
||||
### 5.3 gRPC 실습 예제 동작 흐름
|
||||
예제가 구동되면 서버와 클라이언트 간에 다음과 같은 호출 시퀀스가 순차적으로 실행됩니다:
|
||||
1. **날짜 조회 (`GetDate`)**: 클라이언트가 서버에 날짜 조회를 요청하고, 서버는 자체의 현재 날짜와 시간 문자열을 포맷하여 반환합니다.
|
||||
2. **비밀번호 생성 (`GetRandomPass`)**: 클라이언트가 생성할 무작위 비밀번호의 길이(기본 8자)와 난수 생성 시드값을 전달하면, 서버는 지정된 사양의 임의 문자열을 작성해 반환합니다.
|
||||
3. **난수 생성 (`GetRandom`)**: 서로 다른 위치(Place) 및 시드(Seed) 값을 전달하여 각각 1회씩, 총 2회의 독립적인 난수 생성(의사 난수 정수값) 결과를 반환받아 출력합니다.
|
||||
3. **센싱 데이터 업데이트 (`UpdateSensingData`)**: 클라이언트가 기기 ID("sensor-room-01")와 수집한 온/습도 환경 변수를 전달하면, 서버는 이를 수신하여 화면에 상세 센싱 값을 출력하고 업데이트 완료 성공 응답을 전송합니다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
func AskingDateTime(ctx context.Context, m protoapi.RandomClient) (*protoapi.DateTime, error) {
|
||||
func AskingDateTime(ctx context.Context, m protoapi.IoTServiceClient) (*protoapi.DateTime, error) {
|
||||
request := &protoapi.RequestDateTime{
|
||||
Value: "Please send me the date and time",
|
||||
}
|
||||
@@ -19,7 +19,7 @@ func AskingDateTime(ctx context.Context, m protoapi.RandomClient) (*protoapi.Dat
|
||||
return m.GetDate(ctx, request)
|
||||
}
|
||||
|
||||
func AskPass(ctx context.Context, m protoapi.RandomClient, seed int64, length int64) (*protoapi.RandomPass, error) {
|
||||
func AskPass(ctx context.Context, m protoapi.IoTServiceClient, seed int64, length int64) (*protoapi.RandomPass, error) {
|
||||
request := &protoapi.RequestPass{
|
||||
Seed: seed,
|
||||
Length: length,
|
||||
@@ -28,13 +28,14 @@ func AskPass(ctx context.Context, m protoapi.RandomClient, seed int64, length in
|
||||
return m.GetRandomPass(ctx, request)
|
||||
}
|
||||
|
||||
func AskRandom(ctx context.Context, m protoapi.RandomClient, seed int64, place int64) (*protoapi.RandomInt, error) {
|
||||
request := &protoapi.RandomParams{
|
||||
Seed: seed,
|
||||
Place: place,
|
||||
func AskUpdateSensingData(ctx context.Context, m protoapi.IoTServiceClient, deviceId string, temp float64, humid float64) (*protoapi.SensingResponse, error) {
|
||||
request := &protoapi.SensingData{
|
||||
DeviceId: deviceId,
|
||||
Temperature: temp,
|
||||
Humidity: humid,
|
||||
}
|
||||
|
||||
return m.GetRandom(ctx, request)
|
||||
return m.UpdateSensingData(ctx, request)
|
||||
}
|
||||
|
||||
func ClientRun(addr string) {
|
||||
@@ -44,10 +45,7 @@ func ClientRun(addr string) {
|
||||
return
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
seed := int64(rand.Intn(100))
|
||||
|
||||
client := protoapi.NewRandomClient(conn)
|
||||
client := protoapi.NewIoTServiceClient(conn)
|
||||
r, err := AskingDateTime(context.Background(), client)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -55,6 +53,7 @@ func ClientRun(addr string) {
|
||||
}
|
||||
fmt.Println("Server Date and Time:", r.Value)
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
length := int64(rand.Intn(20))
|
||||
p, err := AskPass(context.Background(), client, 100, length+1)
|
||||
if err != nil {
|
||||
@@ -63,18 +62,11 @@ func ClientRun(addr string) {
|
||||
}
|
||||
fmt.Println("Random Password:", p.Password)
|
||||
|
||||
place := int64(rand.Intn(100))
|
||||
i, err := AskRandom(context.Background(), client, seed, place)
|
||||
res, err := AskUpdateSensingData(context.Background(), client, "sensor-room-01", 24.5, 52.3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Random Integer 1:", i.Value)
|
||||
|
||||
k, err := AskRandom(context.Background(), client, seed, place-1)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("Random Integer 2:", k.Value)
|
||||
fmt.Println("Sensing Update Success:", res.Success)
|
||||
fmt.Println("Sensing Update Message:", res.Message)
|
||||
}
|
||||
|
||||
@@ -50,11 +50,11 @@ func getString(len int64) string {
|
||||
return temp
|
||||
}
|
||||
|
||||
type RandomServer struct {
|
||||
protoapi.UnimplementedRandomServer
|
||||
type IoTServer struct {
|
||||
protoapi.UnimplementedIoTServiceServer
|
||||
}
|
||||
|
||||
func (RandomServer) GetDate(ctx context.Context, r *protoapi.RequestDateTime) (*protoapi.DateTime, error) {
|
||||
func (IoTServer) GetDate(ctx context.Context, r *protoapi.RequestDateTime) (*protoapi.DateTime, error) {
|
||||
currentTime := time.Now()
|
||||
response := &protoapi.DateTime{
|
||||
Value: currentTime.String(),
|
||||
@@ -63,26 +63,18 @@ func (RandomServer) GetDate(ctx context.Context, r *protoapi.RequestDateTime) (*
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (RandomServer) GetRandom(ctx context.Context, r *protoapi.RandomParams) (*protoapi.RandomInt, error) {
|
||||
src := rand.NewSource(r.GetSeed())
|
||||
place := r.GetPlace()
|
||||
temp := random(min, max, src)
|
||||
for {
|
||||
place--
|
||||
if place <= 0 {
|
||||
break
|
||||
}
|
||||
temp = random(min, max, src)
|
||||
}
|
||||
func (IoTServer) UpdateSensingData(ctx context.Context, r *protoapi.SensingData) (*protoapi.SensingResponse, error) {
|
||||
fmt.Printf("Received sensing data - Device: %s, Temp: %.2f°C, Humid: %.2f%%\n", r.GetDeviceId(), r.GetTemperature(), r.GetHumidity())
|
||||
|
||||
response := &protoapi.RandomInt{
|
||||
Value: int64(temp),
|
||||
response := &protoapi.SensingResponse{
|
||||
Success: true,
|
||||
Message: fmt.Sprintf("Sensing data updated successfully for device %s", r.GetDeviceId()),
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (RandomServer) GetRandomPass(ctx context.Context, r *protoapi.RequestPass) (*protoapi.RandomPass, error) {
|
||||
func (IoTServer) GetRandomPass(ctx context.Context, r *protoapi.RequestPass) (*protoapi.RandomPass, error) {
|
||||
rand.Seed(r.GetSeed())
|
||||
temp := getString(r.GetLength())
|
||||
|
||||
@@ -95,8 +87,8 @@ func (RandomServer) GetRandomPass(ctx context.Context, r *protoapi.RequestPass)
|
||||
|
||||
func ServerRun(addr string) {
|
||||
server := grpc.NewServer()
|
||||
var randomServer RandomServer
|
||||
protoapi.RegisterRandomServer(server, randomServer)
|
||||
var iotServer IoTServer
|
||||
protoapi.RegisterIoTServiceServer(server, iotServer)
|
||||
|
||||
reflection.Register(server)
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# 프로젝트 분석 보고서: grpccanary
|
||||
|
||||
## 1. 개요
|
||||
|
||||
`grpccanary`는 **Go 언어로 JSON 처리 → HTTP 서버 → gRPC 서버/클라이언트로 이어지는 학습 여정을 다루는 한국어 튜토리얼 저장소**입니다. 저장소 이름(`grpccanary`)과 달리 실제 내용은 gRPC 단일 주제가 아니라, "데이터 직렬화(JSON) → 웹 서버(HTTP/gin) → 원격 프로시저 호출(gRPC)"로 난이도를 높여가는 3단계 실습 커리큘럼이며, 현재는 **gRPC 파트가 가장 완성도 높게 구현**되어 있습니다.
|
||||
|
||||
저장소 루트에는 이 학습 프로젝트와는 성격이 다른 **`multi-agent-mux`라는 다중 에이전트(Claude Code) 오케스트레이션 인프라**가 함께 자리 잡고 있습니다(`.agents/`, `.mam/` 디렉토리). 이 인프라는 tmux 세션 + MQTT 메시지 브로커를 이용해 여러 AI 에이전트(팀장/리뷰어 역할)가 하나의 작업 저장소를 공유하며 협업하도록 설계된 별도의 도구 체계이며, 실제로 이 보고서를 작성하는 작업(`job 702ea1d8`) 자체도 이 인프라를 통해 위임되었습니다.
|
||||
|
||||
즉 이 저장소는 **"gRPC를 배우기 위한 Go 예제 코드"**와 **"그 예제 코드를 여러 AI 에이전트가 함께 작업하도록 돕는 협업 프레임워크"**가 한 저장소 안에 공존하는 구조입니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 저장소 구조
|
||||
|
||||
```
|
||||
grpccanary/
|
||||
├── README.md # 메인 튜토리얼 (JSON/HTTP/gRPC 개념 설명 + 실행 가이드, 한국어)
|
||||
├── AGENTS.md # LLM 코딩 행동 지침 (일반 원칙)
|
||||
├── go.mod / go.sum # Go 모듈 정의 (module grpccanary, go 1.25.4)
|
||||
├── protoapi.proto # gRPC 서비스 IDL(Protocol Buffers) 정의 원본
|
||||
├── protoapi/ # protoc로 생성된 Go stub 코드
|
||||
│ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go)
|
||||
│ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc)
|
||||
├── obj.json # JSON 예제용 샘플 데이터 파일
|
||||
├── examples/
|
||||
│ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨)
|
||||
│ ├── jsonexample/
|
||||
│ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제
|
||||
│ ├── httpentity/
|
||||
│ │ ├── server.go # gin 기반 HTTP 서버 (전체가 주석 처리된 미완성 스텁)
|
||||
│ │ └── client.go # 패키지 선언만 있는 빈 파일
|
||||
│ └── grpcentity/
|
||||
│ ├── server.go # gRPC 서버 구현 (Random 서비스)
|
||||
│ ├── client.go # gRPC 클라이언트 구현
|
||||
│ └── README.md # gRPC 서버/클라이언트 구현 상세 해설 (한국어)
|
||||
├── docs/
|
||||
│ └── Working with JSON/
|
||||
│ ├── README.md # JSON 관련 학습 자료 (영문)
|
||||
│ └── README-kr.md # JSON 관련 학습 자료 (한글)
|
||||
├── scripts/
|
||||
│ └── generate-env.sh # .env.example → .env 복사 스크립트 (멀티에이전트 인프라용)
|
||||
├── .env.example # 멀티에이전트 인프라(MQTT 브로커 등) 설정 템플릿
|
||||
├── .agents/ # 멀티에이전트 오케스트레이션 규칙·스킬 (아래 4절 참고)
|
||||
└── .mam/ # 멀티에이전트 잡(Job) 레지스트리 및 세션 상태 (런타임 산출물)
|
||||
```
|
||||
|
||||
빌드 확인 결과 `go build ./...` 및 `go vet ./...` 모두 오류 없이 통과했으며, 테스트 파일(`*_test.go`)은 저장소에 존재하지 않습니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 핵심 구성 요소 (학습용 Go 코드)
|
||||
|
||||
### 3.1 진입점 — `examples/main.go`
|
||||
- 프로젝트의 유일한 `main()` 함수. `var port = ":8080"`을 정의하고 있으며, 기본 상태에서는 `jsonexample.JsonParsingExample()`만 호출합니다.
|
||||
- gRPC 예제를 실행하려면 README.md 안내에 따라 `main()` 내부를 수동으로 편집해 `grpcSample()`을 호출하도록 바꿔야 합니다(미사용 import 오류 방지를 위해 `jsonexample` import를 주석 처리해야 함). 즉 **하나의 코드베이스 안에서 학습 단계별로 진입점을 수동 전환하는 방식**으로 설계되어 있습니다.
|
||||
- `grpcSample()` 함수는 `entity.ServerRun(port)`를 고루틴으로 백그라운드 실행한 뒤 1초 대기 후 `entity.ClientRun(...)`을 호출해, 같은 프로세스 안에서 서버·클라이언트가 통신하는 데모를 구성합니다.
|
||||
|
||||
### 3.2 JSON 파싱 예제 — `examples/jsonexample/json_parser.go`
|
||||
- `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다.
|
||||
- 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다.
|
||||
|
||||
### 3.3 HTTP 서버 예제 — `examples/httpentity/`
|
||||
- `server.go`는 `gin-gonic/gin`을 이용한 REST API 서버(정적 파일 서빙 + `/api/randomNumber`, `/api/randomPassword`, `/api/randomDate` 라우트) 초안이 **전체 주석 처리**된 상태로만 존재합니다. 즉 코드는 작성되어 있으나 활성화되지 않은 미완성/보류 상태입니다.
|
||||
- `client.go`는 `package httpentity` 선언 한 줄만 있는 빈 파일입니다.
|
||||
- `go.mod`에는 `gin-gonic/gin` 의존성이 여전히 선언되어 있어, 이 파트가 완전히 폐기된 것이 아니라 추후 재개를 염두에 둔 진행 중(work-in-progress) 상태로 보입니다.
|
||||
|
||||
### 3.4 gRPC 서비스 정의 — `protoapi.proto`
|
||||
- `proto3` 문법으로 `Random`이라는 gRPC 서비스를 정의하며 3개의 RPC 메서드를 제공합니다.
|
||||
- `GetDate(RequestDateTime) returns (DateTime)` — 서버의 현재 날짜/시간 반환
|
||||
- `GetRandom(RandomParams) returns (RandomInt)` — 시드(Seed)와 위치(Place)를 기반으로 한 의사난수 생성
|
||||
- `GetRandomPass(RequestPass) returns (RandomPass)` — 시드와 길이(Length)를 받아 무작위 ASCII 비밀번호 생성
|
||||
- `option go_package = "./protoapi/;protoapi"`로 지정되어 있어, `protoc` 컴파일 시 `protoapi/` 디렉토리에 Go 패키지 `protoapi`가 생성됩니다.
|
||||
- 이미 컴파일된 stub(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 저장소에 커밋되어 있어 `protoc` 재설치 없이 바로 빌드/실행이 가능합니다.
|
||||
|
||||
### 3.5 gRPC 서버 구현 — `examples/grpcentity/server.go`
|
||||
- `RandomServer` 구조체가 `protoapi.UnimplementedRandomServer`를 임베딩하여 3개 RPC 메서드(`GetDate`, `GetRandom`, `GetRandomPass`)를 구현합니다.
|
||||
- `getString(len int64)`은 ASCII 코드 `!`(33)부터 94개 범위 내에서 문자를 뽑아 임의 문자열(비밀번호)을 생성하는 헬퍼입니다.
|
||||
- `ServerRun(addr string)`이 `grpc.NewServer()`로 서버를 만들고 `reflection.Register(server)`로 gRPC reflection(예: `grpcurl` 같은 외부 CLI 디버깅 도구 지원)을 활성화한 뒤 TCP 포트를 리슨합니다.
|
||||
- **주의(코드상 특이점)**: `ServerRun`은 인자로 받은 `addr`을 실제로 사용하지 않고 패키지 전역 변수 `port = ":8080"`으로 리슨합니다(`net.Listen("tcp", port)`). 따라서 현재 코드는 항상 `:8080`에서만 동작하며, 호출부에서 다른 포트를 넘겨도 무시됩니다.
|
||||
- `rand.Seed(r.GetSeed())`(패키지 전역 시드 설정, Go 1.20+에서는 deprecated)와 `rand.NewSource`를 혼용하고 있어 스레드 안전성이나 API 일관성 측면에서 다소 오래된 패턴을 보입니다(학습용 예제이므로 의도된 단순화로 판단됨).
|
||||
|
||||
### 3.6 gRPC 클라이언트 구현 — `examples/grpcentity/client.go`
|
||||
- `grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))`로 평문(TLS 미적용) 채널을 생성합니다(로컬 테스트 목적).
|
||||
- `AskingDateTime`, `AskPass`, `AskRandom` 세 개의 래퍼 함수가 각각 대응하는 RPC를 호출합니다.
|
||||
- `ClientRun(addr)`이 실행 엔트리포인트로, 날짜/시간 조회 1회, 비밀번호 생성 1회, 서로 다른 파라미터로 난수 생성 2회를 순차 호출하며 결과를 표준 출력으로 출력합니다.
|
||||
|
||||
### 3.7 문서 자료
|
||||
- **`README.md`(루트)**: 이야기체(스타트업 개발자 '민우'의 사례)로 gRPC 도입 배경(REST/JSON의 한계, Protobuf 계약, HTTP/2)을 설명한 뒤, Go 버전 요구사항(1.25.4+), 의존성 설치, `main.go` 수동 편집 방법, 실행 명령(`go run ./examples`), 기대 출력 예시, 트러블슈팅(포트 충돌, 모듈 로드 오류)까지 안내하는 실행 가이드로 구성되어 있습니다.
|
||||
- **`examples/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다.
|
||||
- **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 두 번째 레이어 — 멀티에이전트 오케스트레이션 인프라
|
||||
|
||||
저장소에는 학습 콘텐츠와 무관한 **AI 에이전트 협업 인프라**가 함께 포함되어 있습니다.
|
||||
|
||||
- **`AGENTS.md`**: 일반적인 LLM 코딩 행동 지침(가정하지 말 것, 최소 변경, 외과적 수정 등)을 규정합니다.
|
||||
- **`.agents/MULTI_AGENT_RULES.md`(+ 한국어판)**: MQTT 메시징 백플레인과 tmux 기반 다중 에이전트 협업 프로토콜을 정의합니다. 총괄 매니저(Orchestrator) → 팀장(개발/리뷰) → 작업 위임 및 리뷰 루프 → 완료 보고로 이어지는 워크플로우, Job 레지스트리(`.mam/jobs/<id>.json`, `fcntl` 파일 락), 세션 레지스트리(`.mam/agent-sessions.db`, SQLite WAL), HMAC-SHA256 기반 메시지 인증(PoC 모드에서는 비활성) 등을 상세히 규정합니다.
|
||||
- **`.agents/skills/`**: `multi-agent-mux-{create,delegate-job,loop,monitor,resume,status,stop}` 등 실제 세션 생성·작업 위임·모니터링·중지를 수행하는 스킬(스크립트) 모음입니다.
|
||||
- **`.mam/`**: 위 인프라의 런타임 상태 저장소로, `jobs/`(작업 레지스트리 및 브리프 파일), `agent-sessions.yaml`/`.db`(세션 상태), `agent_homes/`(에이전트별 메모리), `delegate_job_logs/`(위임 감사 로그)를 포함합니다. 이번 작업 브리프(`.mam/jobs/702ea1d8/brief.md`) 역시 이 구조를 통해 전달되었습니다.
|
||||
- **`scripts/generate-env.sh`, `.env.example`**: 이 인프라가 사용하는 MQTT 브로커 접속 정보, 경로 설정 등을 `.env`로 초기화하는 헬퍼입니다. 실제 비밀 값은 `.env`(git-ignored)에만 두고 `.env.example`에는 플레이스홀더만 커밋하도록 설계되어 있습니다.
|
||||
|
||||
**참고**: 새로 추가된 `.gitignore`는 `.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `examples/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음).
|
||||
|
||||
---
|
||||
|
||||
## 5. 실행 방법
|
||||
|
||||
### 5.1 사전 준비
|
||||
```bash
|
||||
go version # Go 1.25.4 이상 필요
|
||||
go mod download # 의존성 다운로드
|
||||
```
|
||||
|
||||
### 5.2 JSON 예제 실행 (기본값, 별도 수정 불필요)
|
||||
```bash
|
||||
go run ./examples
|
||||
```
|
||||
`examples/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다.
|
||||
|
||||
### 5.3 gRPC 예제 실행 (수동 편집 필요)
|
||||
1. `examples/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경.
|
||||
2. 저장 후 실행:
|
||||
```bash
|
||||
go run ./examples
|
||||
```
|
||||
3. 내부적으로 `:8080` 포트에서 gRPC 서버(고루틴)가 기동되고, 1초 후 클라이언트가 `GetDate`, `GetRandomPass`, `GetRandom`(2회) 순으로 RPC를 호출하며 결과를 출력합니다.
|
||||
4. 포트 충돌 시(`bind: address already in use`) `examples/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능).
|
||||
|
||||
### 5.4 HTTP 예제
|
||||
`httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다.
|
||||
|
||||
### 5.5 `.proto` 재컴파일 (선택)
|
||||
`.proto` 정의를 수정하고 stub을 재생성하려면:
|
||||
```bash
|
||||
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
|
||||
--go-grpc_opt=paths=source_relative protoapi.proto
|
||||
```
|
||||
사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `examples/grpcentity/README.md` 참고).
|
||||
|
||||
---
|
||||
|
||||
## 6. 주요 관찰 사항 및 특이점
|
||||
|
||||
1. **단일 진입점, 수동 전환 방식**: `examples/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다.
|
||||
2. **`ServerRun(addr)`의 `addr` 인자 미사용**: gRPC 서버는 전달받은 인자 대신 패키지 전역 `port` 변수로 리슨하므로, 함수 시그니처와 실제 동작이 일치하지 않는 잠재적 혼동 요소입니다.
|
||||
3. **HTTP 파트 미완성**: `gin` 의존성은 `go.mod`에 존재하지만 실제 코드는 비활성 상태로, 커리큘럼상 "다음 실습 예정" 단계로 보입니다.
|
||||
4. **테스트 부재**: 저장소 전체에 자동화된 테스트(`*_test.go`)가 없어, 코드 정상 동작 여부는 수동 실행(`go run`)과 콘솔 출력 확인에 의존합니다. `go build ./...`, `go vet ./...`는 통과합니다.
|
||||
5. **레거시 API 사용**: `rand.Seed(...)`(전역 시드 설정) 등 Go 최신 버전에서 권장되지 않는(deprecated) 패턴이 사용되고 있으나, 학습용 예제의 단순성을 위한 의도적 선택으로 보입니다.
|
||||
6. **이중 성격의 저장소**: 순수 학습 콘텐츠(gRPC/JSON/HTTP 튜토리얼)와 AI 에이전트 협업 인프라(multi-agent-mux)가 한 저장소에 공존하며, 두 영역은 서로 기능적으로 독립적입니다. 협업 인프라(`.agents/`, `.mam/`)는 이 학습 프로젝트를 대상으로 여러 AI 에이전트가 작업을 위임받고 결과를 보고하는 용도로 사용되고 있습니다(본 보고서 작성 작업 자체가 그 예시).
|
||||
+9
-10
@@ -2,23 +2,23 @@ syntax = "proto3";
|
||||
|
||||
option go_package = "./protoapi/;protoapi";
|
||||
|
||||
service Random {
|
||||
service IoTService {
|
||||
rpc GetDate (RequestDateTime) returns (DateTime);
|
||||
rpc GetRandom (RandomParams) returns (RandomInt);
|
||||
rpc UpdateSensingData (SensingData) returns (SensingResponse);
|
||||
rpc GetRandomPass (RequestPass) returns (RandomPass);
|
||||
}
|
||||
|
||||
// For random number
|
||||
message RandomParams {
|
||||
int64 Seed = 1;
|
||||
int64 Place = 2;
|
||||
message SensingData {
|
||||
string DeviceId = 1;
|
||||
double Temperature = 2;
|
||||
double Humidity = 3;
|
||||
}
|
||||
|
||||
message RandomInt {
|
||||
int64 Value = 1;
|
||||
message SensingResponse {
|
||||
bool Success = 1;
|
||||
string Message = 2;
|
||||
}
|
||||
|
||||
// For date time
|
||||
message DateTime {
|
||||
string Value = 1;
|
||||
}
|
||||
@@ -27,7 +27,6 @@ message RequestDateTime {
|
||||
string Value = 2;
|
||||
}
|
||||
|
||||
// For random password
|
||||
message RequestPass {
|
||||
int64 Seed = 1;
|
||||
int64 Length = 8;
|
||||
|
||||
+104
-189
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v3.21.12
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.27.2
|
||||
// source: protoapi.proto
|
||||
|
||||
package protoapi
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -20,34 +21,31 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// For random number
|
||||
type RandomParams struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
type SensingData struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DeviceId string `protobuf:"bytes,1,opt,name=DeviceId,proto3" json:"DeviceId,omitempty"`
|
||||
Temperature float64 `protobuf:"fixed64,2,opt,name=Temperature,proto3" json:"Temperature,omitempty"`
|
||||
Humidity float64 `protobuf:"fixed64,3,opt,name=Humidity,proto3" json:"Humidity,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Seed int64 `protobuf:"varint,1,opt,name=Seed,proto3" json:"Seed,omitempty"`
|
||||
Place int64 `protobuf:"varint,2,opt,name=Place,proto3" json:"Place,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RandomParams) Reset() {
|
||||
*x = RandomParams{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
func (x *SensingData) Reset() {
|
||||
*x = SensingData{}
|
||||
mi := &file_protoapi_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RandomParams) String() string {
|
||||
func (x *SensingData) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RandomParams) ProtoMessage() {}
|
||||
func (*SensingData) ProtoMessage() {}
|
||||
|
||||
func (x *RandomParams) ProtoReflect() protoreflect.Message {
|
||||
func (x *SensingData) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -57,51 +55,56 @@ func (x *RandomParams) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RandomParams.ProtoReflect.Descriptor instead.
|
||||
func (*RandomParams) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use SensingData.ProtoReflect.Descriptor instead.
|
||||
func (*SensingData) Descriptor() ([]byte, []int) {
|
||||
return file_protoapi_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RandomParams) GetSeed() int64 {
|
||||
func (x *SensingData) GetDeviceId() string {
|
||||
if x != nil {
|
||||
return x.Seed
|
||||
return x.DeviceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SensingData) GetTemperature() float64 {
|
||||
if x != nil {
|
||||
return x.Temperature
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RandomParams) GetPlace() int64 {
|
||||
func (x *SensingData) GetHumidity() float64 {
|
||||
if x != nil {
|
||||
return x.Place
|
||||
return x.Humidity
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type RandomInt struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
type SensingResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Success bool `protobuf:"varint,1,opt,name=Success,proto3" json:"Success,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value int64 `protobuf:"varint,1,opt,name=Value,proto3" json:"Value,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RandomInt) Reset() {
|
||||
*x = RandomInt{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
func (x *SensingResponse) Reset() {
|
||||
*x = SensingResponse{}
|
||||
mi := &file_protoapi_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RandomInt) String() string {
|
||||
func (x *SensingResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RandomInt) ProtoMessage() {}
|
||||
func (*SensingResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RandomInt) ProtoReflect() protoreflect.Message {
|
||||
func (x *SensingResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -111,35 +114,38 @@ func (x *RandomInt) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RandomInt.ProtoReflect.Descriptor instead.
|
||||
func (*RandomInt) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use SensingResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SensingResponse) Descriptor() ([]byte, []int) {
|
||||
return file_protoapi_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *RandomInt) GetValue() int64 {
|
||||
func (x *SensingResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
return x.Success
|
||||
}
|
||||
return 0
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SensingResponse) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// For date time
|
||||
type DateTime struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Value string `protobuf:"bytes,1,opt,name=Value,proto3" json:"Value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DateTime) Reset() {
|
||||
*x = DateTime{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_protoapi_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *DateTime) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
@@ -149,7 +155,7 @@ func (*DateTime) ProtoMessage() {}
|
||||
|
||||
func (x *DateTime) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -172,21 +178,18 @@ func (x *DateTime) GetValue() string {
|
||||
}
|
||||
|
||||
type RequestDateTime struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Value string `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RequestDateTime) Reset() {
|
||||
*x = RequestDateTime{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_protoapi_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RequestDateTime) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
@@ -196,7 +199,7 @@ func (*RequestDateTime) ProtoMessage() {}
|
||||
|
||||
func (x *RequestDateTime) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -218,24 +221,20 @@ func (x *RequestDateTime) GetValue() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// For random password
|
||||
type RequestPass struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Seed int64 `protobuf:"varint,1,opt,name=Seed,proto3" json:"Seed,omitempty"`
|
||||
Length int64 `protobuf:"varint,8,opt,name=Length,proto3" json:"Length,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RequestPass) Reset() {
|
||||
*x = RequestPass{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_protoapi_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RequestPass) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
@@ -245,7 +244,7 @@ func (*RequestPass) ProtoMessage() {}
|
||||
|
||||
func (x *RequestPass) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -275,21 +274,18 @@ func (x *RequestPass) GetLength() int64 {
|
||||
}
|
||||
|
||||
type RandomPass struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Password string `protobuf:"bytes,1,opt,name=Password,proto3" json:"Password,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RandomPass) Reset() {
|
||||
*x = RandomPass{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_protoapi_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RandomPass) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
@@ -299,7 +295,7 @@ func (*RandomPass) ProtoMessage() {}
|
||||
|
||||
func (x *RandomPass) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_protoapi_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -323,66 +319,60 @@ func (x *RandomPass) GetPassword() string {
|
||||
|
||||
var File_protoapi_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_protoapi_proto_rawDesc = []byte{
|
||||
0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x22, 0x38, 0x0a, 0x0c, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
|
||||
0x53, 0x65, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x05, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x22, 0x21, 0x0a, 0x09, 0x52, 0x61,
|
||||
0x6e, 0x64, 0x6f, 0x6d, 0x49, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x20, 0x0a,
|
||||
0x08, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
||||
0x27, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69,
|
||||
0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x39, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x65, 0x65, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x4c,
|
||||
0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x4c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x22, 0x28, 0x0a, 0x0a, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x61, 0x73,
|
||||
0x73, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x32, 0x84, 0x01,
|
||||
0x0a, 0x06, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x44,
|
||||
0x61, 0x74, 0x65, 0x12, 0x10, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74,
|
||||
0x65, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x09, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x12, 0x26, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x0d, 0x2e,
|
||||
0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x0a, 0x2e, 0x52,
|
||||
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x49, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52,
|
||||
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x12, 0x0c, 0x2e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x50, 0x61, 0x73, 0x73, 0x1a, 0x0b, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d,
|
||||
0x50, 0x61, 0x73, 0x73, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
const file_protoapi_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x0eprotoapi.proto\"g\n" +
|
||||
"\vSensingData\x12\x1a\n" +
|
||||
"\bDeviceId\x18\x01 \x01(\tR\bDeviceId\x12 \n" +
|
||||
"\vTemperature\x18\x02 \x01(\x01R\vTemperature\x12\x1a\n" +
|
||||
"\bHumidity\x18\x03 \x01(\x01R\bHumidity\"E\n" +
|
||||
"\x0fSensingResponse\x12\x18\n" +
|
||||
"\aSuccess\x18\x01 \x01(\bR\aSuccess\x12\x18\n" +
|
||||
"\aMessage\x18\x02 \x01(\tR\aMessage\" \n" +
|
||||
"\bDateTime\x12\x14\n" +
|
||||
"\x05Value\x18\x01 \x01(\tR\x05Value\"'\n" +
|
||||
"\x0fRequestDateTime\x12\x14\n" +
|
||||
"\x05Value\x18\x02 \x01(\tR\x05Value\"9\n" +
|
||||
"\vRequestPass\x12\x12\n" +
|
||||
"\x04Seed\x18\x01 \x01(\x03R\x04Seed\x12\x16\n" +
|
||||
"\x06Length\x18\b \x01(\x03R\x06Length\"(\n" +
|
||||
"\n" +
|
||||
"RandomPass\x12\x1a\n" +
|
||||
"\bPassword\x18\x01 \x01(\tR\bPassword2\x95\x01\n" +
|
||||
"\n" +
|
||||
"IoTService\x12&\n" +
|
||||
"\aGetDate\x12\x10.RequestDateTime\x1a\t.DateTime\x123\n" +
|
||||
"\x11UpdateSensingData\x12\f.SensingData\x1a\x10.SensingResponse\x12*\n" +
|
||||
"\rGetRandomPass\x12\f.RequestPass\x1a\v.RandomPassB\x16Z\x14./protoapi/;protoapib\x06proto3"
|
||||
|
||||
var (
|
||||
file_protoapi_proto_rawDescOnce sync.Once
|
||||
file_protoapi_proto_rawDescData = file_protoapi_proto_rawDesc
|
||||
file_protoapi_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_protoapi_proto_rawDescGZIP() []byte {
|
||||
file_protoapi_proto_rawDescOnce.Do(func() {
|
||||
file_protoapi_proto_rawDescData = protoimpl.X.CompressGZIP(file_protoapi_proto_rawDescData)
|
||||
file_protoapi_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_protoapi_proto_rawDesc), len(file_protoapi_proto_rawDesc)))
|
||||
})
|
||||
return file_protoapi_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_protoapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_protoapi_proto_goTypes = []interface{}{
|
||||
(*RandomParams)(nil), // 0: RandomParams
|
||||
(*RandomInt)(nil), // 1: RandomInt
|
||||
var file_protoapi_proto_goTypes = []any{
|
||||
(*SensingData)(nil), // 0: SensingData
|
||||
(*SensingResponse)(nil), // 1: SensingResponse
|
||||
(*DateTime)(nil), // 2: DateTime
|
||||
(*RequestDateTime)(nil), // 3: RequestDateTime
|
||||
(*RequestPass)(nil), // 4: RequestPass
|
||||
(*RandomPass)(nil), // 5: RandomPass
|
||||
}
|
||||
var file_protoapi_proto_depIdxs = []int32{
|
||||
3, // 0: Random.GetDate:input_type -> RequestDateTime
|
||||
0, // 1: Random.GetRandom:input_type -> RandomParams
|
||||
4, // 2: Random.GetRandomPass:input_type -> RequestPass
|
||||
2, // 3: Random.GetDate:output_type -> DateTime
|
||||
1, // 4: Random.GetRandom:output_type -> RandomInt
|
||||
5, // 5: Random.GetRandomPass:output_type -> RandomPass
|
||||
3, // 0: IoTService.GetDate:input_type -> RequestDateTime
|
||||
0, // 1: IoTService.UpdateSensingData:input_type -> SensingData
|
||||
4, // 2: IoTService.GetRandomPass:input_type -> RequestPass
|
||||
2, // 3: IoTService.GetDate:output_type -> DateTime
|
||||
1, // 4: IoTService.UpdateSensingData:output_type -> SensingResponse
|
||||
5, // 5: IoTService.GetRandomPass:output_type -> RandomPass
|
||||
3, // [3:6] is the sub-list for method output_type
|
||||
0, // [0:3] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
@@ -395,85 +385,11 @@ func file_protoapi_proto_init() {
|
||||
if File_protoapi_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_protoapi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RandomParams); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_protoapi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RandomInt); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_protoapi_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DateTime); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_protoapi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RequestDateTime); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_protoapi_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RequestPass); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_protoapi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RandomPass); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_protoapi_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_protoapi_proto_rawDesc), len(file_protoapi_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
@@ -484,7 +400,6 @@ func file_protoapi_proto_init() {
|
||||
MessageInfos: file_protoapi_proto_msgTypes,
|
||||
}.Build()
|
||||
File_protoapi_proto = out.File
|
||||
file_protoapi_proto_rawDesc = nil
|
||||
file_protoapi_proto_goTypes = nil
|
||||
file_protoapi_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v3.21.12
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v5.27.2
|
||||
// source: protoapi.proto
|
||||
|
||||
package protoapi
|
||||
@@ -19,177 +19,177 @@ import (
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Random_GetDate_FullMethodName = "/Random/GetDate"
|
||||
Random_GetRandom_FullMethodName = "/Random/GetRandom"
|
||||
Random_GetRandomPass_FullMethodName = "/Random/GetRandomPass"
|
||||
IoTService_GetDate_FullMethodName = "/IoTService/GetDate"
|
||||
IoTService_UpdateSensingData_FullMethodName = "/IoTService/UpdateSensingData"
|
||||
IoTService_GetRandomPass_FullMethodName = "/IoTService/GetRandomPass"
|
||||
)
|
||||
|
||||
// RandomClient is the client API for Random service.
|
||||
// IoTServiceClient is the client API for IoTService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type RandomClient interface {
|
||||
type IoTServiceClient interface {
|
||||
GetDate(ctx context.Context, in *RequestDateTime, opts ...grpc.CallOption) (*DateTime, error)
|
||||
GetRandom(ctx context.Context, in *RandomParams, opts ...grpc.CallOption) (*RandomInt, error)
|
||||
UpdateSensingData(ctx context.Context, in *SensingData, opts ...grpc.CallOption) (*SensingResponse, error)
|
||||
GetRandomPass(ctx context.Context, in *RequestPass, opts ...grpc.CallOption) (*RandomPass, error)
|
||||
}
|
||||
|
||||
type randomClient struct {
|
||||
type ioTServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewRandomClient(cc grpc.ClientConnInterface) RandomClient {
|
||||
return &randomClient{cc}
|
||||
func NewIoTServiceClient(cc grpc.ClientConnInterface) IoTServiceClient {
|
||||
return &ioTServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *randomClient) GetDate(ctx context.Context, in *RequestDateTime, opts ...grpc.CallOption) (*DateTime, error) {
|
||||
func (c *ioTServiceClient) GetDate(ctx context.Context, in *RequestDateTime, opts ...grpc.CallOption) (*DateTime, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DateTime)
|
||||
err := c.cc.Invoke(ctx, Random_GetDate_FullMethodName, in, out, cOpts...)
|
||||
err := c.cc.Invoke(ctx, IoTService_GetDate_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *randomClient) GetRandom(ctx context.Context, in *RandomParams, opts ...grpc.CallOption) (*RandomInt, error) {
|
||||
func (c *ioTServiceClient) UpdateSensingData(ctx context.Context, in *SensingData, opts ...grpc.CallOption) (*SensingResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RandomInt)
|
||||
err := c.cc.Invoke(ctx, Random_GetRandom_FullMethodName, in, out, cOpts...)
|
||||
out := new(SensingResponse)
|
||||
err := c.cc.Invoke(ctx, IoTService_UpdateSensingData_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *randomClient) GetRandomPass(ctx context.Context, in *RequestPass, opts ...grpc.CallOption) (*RandomPass, error) {
|
||||
func (c *ioTServiceClient) GetRandomPass(ctx context.Context, in *RequestPass, opts ...grpc.CallOption) (*RandomPass, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RandomPass)
|
||||
err := c.cc.Invoke(ctx, Random_GetRandomPass_FullMethodName, in, out, cOpts...)
|
||||
err := c.cc.Invoke(ctx, IoTService_GetRandomPass_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// RandomServer is the server API for Random service.
|
||||
// All implementations must embed UnimplementedRandomServer
|
||||
// IoTServiceServer is the server API for IoTService service.
|
||||
// All implementations must embed UnimplementedIoTServiceServer
|
||||
// for forward compatibility.
|
||||
type RandomServer interface {
|
||||
type IoTServiceServer interface {
|
||||
GetDate(context.Context, *RequestDateTime) (*DateTime, error)
|
||||
GetRandom(context.Context, *RandomParams) (*RandomInt, error)
|
||||
UpdateSensingData(context.Context, *SensingData) (*SensingResponse, error)
|
||||
GetRandomPass(context.Context, *RequestPass) (*RandomPass, error)
|
||||
mustEmbedUnimplementedRandomServer()
|
||||
mustEmbedUnimplementedIoTServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedRandomServer must be embedded to have
|
||||
// UnimplementedIoTServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedRandomServer struct{}
|
||||
type UnimplementedIoTServiceServer struct{}
|
||||
|
||||
func (UnimplementedRandomServer) GetDate(context.Context, *RequestDateTime) (*DateTime, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDate not implemented")
|
||||
func (UnimplementedIoTServiceServer) GetDate(context.Context, *RequestDateTime) (*DateTime, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetDate not implemented")
|
||||
}
|
||||
func (UnimplementedRandomServer) GetRandom(context.Context, *RandomParams) (*RandomInt, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRandom not implemented")
|
||||
func (UnimplementedIoTServiceServer) UpdateSensingData(context.Context, *SensingData) (*SensingResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateSensingData not implemented")
|
||||
}
|
||||
func (UnimplementedRandomServer) GetRandomPass(context.Context, *RequestPass) (*RandomPass, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRandomPass not implemented")
|
||||
func (UnimplementedIoTServiceServer) GetRandomPass(context.Context, *RequestPass) (*RandomPass, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetRandomPass not implemented")
|
||||
}
|
||||
func (UnimplementedRandomServer) mustEmbedUnimplementedRandomServer() {}
|
||||
func (UnimplementedRandomServer) testEmbeddedByValue() {}
|
||||
func (UnimplementedIoTServiceServer) mustEmbedUnimplementedIoTServiceServer() {}
|
||||
func (UnimplementedIoTServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeRandomServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to RandomServer will
|
||||
// UnsafeIoTServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to IoTServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeRandomServer interface {
|
||||
mustEmbedUnimplementedRandomServer()
|
||||
type UnsafeIoTServiceServer interface {
|
||||
mustEmbedUnimplementedIoTServiceServer()
|
||||
}
|
||||
|
||||
func RegisterRandomServer(s grpc.ServiceRegistrar, srv RandomServer) {
|
||||
// If the following call pancis, it indicates UnimplementedRandomServer was
|
||||
func RegisterIoTServiceServer(s grpc.ServiceRegistrar, srv IoTServiceServer) {
|
||||
// If the following call panics, it indicates UnimplementedIoTServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Random_ServiceDesc, srv)
|
||||
s.RegisterService(&IoTService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Random_GetDate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _IoTService_GetDate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RequestDateTime)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RandomServer).GetDate(ctx, in)
|
||||
return srv.(IoTServiceServer).GetDate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Random_GetDate_FullMethodName,
|
||||
FullMethod: IoTService_GetDate_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RandomServer).GetDate(ctx, req.(*RequestDateTime))
|
||||
return srv.(IoTServiceServer).GetDate(ctx, req.(*RequestDateTime))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Random_GetRandom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RandomParams)
|
||||
func _IoTService_UpdateSensingData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SensingData)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RandomServer).GetRandom(ctx, in)
|
||||
return srv.(IoTServiceServer).UpdateSensingData(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Random_GetRandom_FullMethodName,
|
||||
FullMethod: IoTService_UpdateSensingData_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RandomServer).GetRandom(ctx, req.(*RandomParams))
|
||||
return srv.(IoTServiceServer).UpdateSensingData(ctx, req.(*SensingData))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Random_GetRandomPass_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _IoTService_GetRandomPass_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RequestPass)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RandomServer).GetRandomPass(ctx, in)
|
||||
return srv.(IoTServiceServer).GetRandomPass(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Random_GetRandomPass_FullMethodName,
|
||||
FullMethod: IoTService_GetRandomPass_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RandomServer).GetRandomPass(ctx, req.(*RequestPass))
|
||||
return srv.(IoTServiceServer).GetRandomPass(ctx, req.(*RequestPass))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Random_ServiceDesc is the grpc.ServiceDesc for Random service.
|
||||
// IoTService_ServiceDesc is the grpc.ServiceDesc for IoTService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Random_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Random",
|
||||
HandlerType: (*RandomServer)(nil),
|
||||
var IoTService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "IoTService",
|
||||
HandlerType: (*IoTServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetDate",
|
||||
Handler: _Random_GetDate_Handler,
|
||||
Handler: _IoTService_GetDate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetRandom",
|
||||
Handler: _Random_GetRandom_Handler,
|
||||
MethodName: "UpdateSensingData",
|
||||
Handler: _IoTService_UpdateSensingData_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetRandomPass",
|
||||
Handler: _Random_GetRandomPass_Handler,
|
||||
Handler: _IoTService_GetRandomPass_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# generate-env.sh — create a local .env from the committed .env.example template.
|
||||
#
|
||||
# Behaviour:
|
||||
# - .env absent → copy .env.example to .env, print the path.
|
||||
# - .env present → no-op (leaves your edits intact), exit 0.
|
||||
# - .env present --force → overwrite .env from .env.example (backs up to .env.bak).
|
||||
#
|
||||
# Paths are resolved relative to this script (repo root = parent of deploy/),
|
||||
# so it works regardless of the caller's cwd.
|
||||
#
|
||||
# Usage: deploy/generate-env.sh [--force] [-h|--help]
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SRC="$REPO_ROOT/.env.example"
|
||||
DST="$REPO_ROOT/.env"
|
||||
|
||||
FORCE=0
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--force) FORCE=1; shift ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 [--force]"
|
||||
echo " Create .env from .env.example. --force overwrites an existing .env."
|
||||
exit 0 ;;
|
||||
*) echo "ERROR: unknown arg: $1" >&2; echo "Usage: $0 [--force]" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -f "$SRC" ] || { echo "ERROR: template not found: $SRC" >&2; exit 1; }
|
||||
|
||||
if [ -f "$DST" ] && [ "$FORCE" != "1" ]; then
|
||||
echo "no-op: $DST already exists (use --force to overwrite)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f "$DST" ] && [ "$FORCE" = "1" ]; then
|
||||
cp -p "$DST" "$DST.bak"
|
||||
echo "backed up existing .env -> $DST.bak"
|
||||
fi
|
||||
|
||||
cp "$SRC" "$DST"
|
||||
echo "created: $DST"
|
||||
echo "Next: edit $DST and fill in any secrets (look for 'replace_me')."
|
||||
Reference in New Issue
Block a user