From 8bb11fe20525390b6340e1b529ddaded994cdac1 Mon Sep 17 00:00:00 2001 From: Godopu Date: Fri, 17 Jul 2026 19:21:21 +0900 Subject: [PATCH] refactor: rename examples/ directory to lib/ and update all path references --- README.md | 14 +++++----- docs/GRPC.md | 18 ++++++------- docs/HTTP.md | 4 +-- docs/JSON.md | 4 +-- {examples => lib}/grpcentity/README.md | 8 +++--- {examples => lib}/grpcentity/client.go | 2 +- {examples => lib}/grpcentity/protoapi.proto | 0 .../grpcentity/protoapi/protoapi.pb.go | 0 .../grpcentity/protoapi/protoapi_grpc.pb.go | 0 {examples => lib}/grpcentity/server.go | 2 +- {examples => lib}/httpentity/README.md | 8 +++--- {examples => lib}/httpentity/client.go | 0 {examples => lib}/httpentity/server.go | 0 {examples => lib}/jsonexample/README.md | 8 +++--- {examples => lib}/jsonexample/json_parser.go | 0 {examples => lib}/main.go | 4 +-- project_analysis_report.md | 26 +++++++++---------- 17 files changed, 49 insertions(+), 49 deletions(-) rename {examples => lib}/grpcentity/README.md (83%) rename {examples => lib}/grpcentity/client.go (99%) rename {examples => lib}/grpcentity/protoapi.proto (100%) rename {examples => lib}/grpcentity/protoapi/protoapi.pb.go (100%) rename {examples => lib}/grpcentity/protoapi/protoapi_grpc.pb.go (100%) rename {examples => lib}/grpcentity/server.go (99%) rename {examples => lib}/httpentity/README.md (82%) rename {examples => lib}/httpentity/client.go (100%) rename {examples => lib}/httpentity/server.go (100%) rename {examples => lib}/jsonexample/README.md (81%) rename {examples => lib}/jsonexample/json_parser.go (100%) rename {examples => lib}/main.go (90%) diff --git a/README.md b/README.md index 0ae4a14..72aae59 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ grpccanary/ ├── README.md # 본 프로젝트 종합 소개 및 실행 가이드 (교육용) ├── go.mod / go.sum # Go 모듈 의존성 정의 (Go 1.25.4+) -├── examples/ +├── lib/ │ ├── main.go # 학습 예제 통합 실행 진입점 (수동 전환) │ ├── jsonexample/ # 1단계: JSON 데이터 다루기 실습 예제 │ ├── httpentity/ # 2단계: HTTP & Gin 웹 서버 실습 예제 (WIP) @@ -39,13 +39,13 @@ grpccanary/ └── GRPC.md # 3단계: gRPC 통신 구현 상세 가이드 ``` -### 1단계: JSON 데이터 다루기 (`examples/jsonexample`) +### 1단계: JSON 데이터 다루기 (`lib/jsonexample`) * Go 표준 라이브러리인 `encoding/json`을 활용하여 구조체(Struct)와 JSON 데이터 간의 마샬링(Serialization) 및 언마샬링(Deserialization) 기법을 학습합니다. -### 2단계: HTTP & Gin 웹 서버 (`examples/httpentity`) +### 2단계: HTTP & Gin 웹 서버 (`lib/httpentity`) * 대중적인 Go 웹 프레임워크 `gin-gonic`을 활용해 RESTful API 사양을 구축하는 방법을 이해합니다. (현재 주석 해제 후 실습하도록 설계된 Work-in-Progress 단계) -### 3단계: gRPC 통신 구현 (`examples/grpcentity`) +### 3단계: gRPC 통신 구현 (`lib/grpcentity`) * `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다. * `.proto` 정의를 바탕으로 통신 스키마 계약을 강제하고, Go 언어로 gRPC 서버를 띄워 클라이언트가 날짜/시간, 무작위 비밀번호 및 정수 데이터를 실시간 원격 호출로 송수신하는 분산 통신 기초를 학습합니다. @@ -73,13 +73,13 @@ grpccanary/ ### 2. 실습 예제 실행 방법 (진입점 전환) 이 프로젝트는 교육적 목적을 위해 **하나의 `main.go` 파일 안에서 주석 처리를 통해 학습 단계를 수동 전환**하여 실행하도록 설계되어 있습니다. -1. **[examples/main.go](examples/main.go)** 파일을 엽니다. +1. **[lib/main.go](lib/main.go)** 파일을 엽니다. 2. 아래와 같이 실행하고자 하는 예제의 주석을 해제하고 다른 예제는 주석 처리합니다. * *JSON 예제 실행 시*: `jsonexample.JsonParsingExample()` 활성화 * *gRPC 예제 실행 시*: `grpcSample()` 활성화 (미사용 import 에러를 피하기 위해 `jsonexample` import는 주석 처리 필요) 3. 루트 디렉토리에서 다음 명령어로 실행합니다: ```bash - go run ./examples + go run ./lib ``` ### 3. gRPC 예제 동작 흐름 및 기대 출력 @@ -106,4 +106,4 @@ Sensing Update Message: Sensing data updated successfully for device sensor-room * **[docs/JSON.md](docs/JSON.md)**: 1단계 JSON 데이터 다루기 상세 학습 가이드 * **[docs/HTTP.md](docs/HTTP.md)**: 2단계 HTTP & Gin 웹 프레임워크 상세 학습 가이드 * **[docs/GRPC.md](docs/GRPC.md)**: 3단계 gRPC & Protobuf 상세 학습 가이드 (컴파일 절차 및 소스코드 구현체 분석 포함) -* **[examples/grpcentity/README.md](examples/grpcentity/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크 +* **[lib/grpcentity/README.md](lib/grpcentity/README.md)**: gRPC 실습 디렉토리 안내 및 `docs/GRPC.md` 심화 가이드로의 링크 diff --git a/docs/GRPC.md b/docs/GRPC.md index 38ce209..0693c6c 100644 --- a/docs/GRPC.md +++ b/docs/GRPC.md @@ -82,7 +82,7 @@ gRPC는 HTTP/2를 기반으로 구축된 구글의 고성능 오픈소스 원격 ### 3.4 명세서 소스코드 및 구체적 분석 -실습 디렉토리 내에 선언된 [protoapi.proto](../examples/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다. +실습 디렉토리 내에 선언된 [protoapi.proto](../lib/grpcentity/protoapi.proto) 명세서 코드는 앞서 기획한 `IoTService` 통신 구조를 수립하기 위해 다음과 같이 사양을 기재해 둡니다. ```proto syntax = "proto3"; @@ -175,7 +175,7 @@ gRPC 빌드 및 코드 생성 환경을 구축하기 위해 사용되는 세 가 작성된 스키마 명세를 빌드하여 Go 소스코드를 생성하기 위해 다음 명령어를 구동합니다: ```bash # 해당 실습 디렉터리로 이동 후 컴파일 실행 -cd examples/grpcentity +cd lib/grpcentity protoc --go_out=. --go-grpc_out=. protoapi.proto ``` @@ -186,7 +186,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto **Go 패키지 지정 옵션과의 결합 규칙**: 해당 출력 경로 옵션들은 단독으로 파일의 최종 위치를 고정하지 않습니다. 컴파일러는 지정된 기준 경로(예: `.`)에 `.proto` 스펙 내부의 `option go_package = "./protoapi;protoapi"` 설정값을 조합하여 최종 디렉터리 경로를 생성합니다. -이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `examples/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다: +이에 따라 **컴파일 대상 디렉터리(`.`)**와 **상세 패키지 주소(`./protoapi`)**가 결합되어 `lib/grpcentity/protoapi/` 경로가 자동 생성되며, 그 하위에 다음 소스코드들이 정상 배치됩니다: * `protoapi.pb.go`: 명세에 정의된 메시지(Message) 규격을 Go 구조체로 변환한 파일입니다. * `protoapi_grpc.pb.go`: 클라이언트와 서버 통신을 위한 원격 호출(Service) 규격을 구현한 파일입니다. @@ -196,7 +196,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto 컴파일러를 통해 통신을 위한 스터브(Stub) 코드가 확보되었으므로, 이를 기반으로 서버와 클라이언트의 비즈니스 로직을 연결하는 상세 코드를 검토합니다. -### 5.1 gRPC 서버 구현 분석 ([server.go](../examples/grpcentity/server.go)) +### 5.1 gRPC 서버 구현 분석 ([server.go](../lib/grpcentity/server.go)) * **서버 서비스 인터페이스 매핑 구조체 (`IoTServer`)**: ```go @@ -240,7 +240,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto * **쉬운 설명**: `:8080` 포트로 통하는 소켓(전화선)을 개통하고, 기기들의 전화(접속 및 호출)가 오기를 기다리며 대기 상태로 들어가는 서버 구동 시작점입니다. * **상세 설명**: 지정된 포트(기본 포트 `:8080`)의 TCP 소켓 포트를 활성화하고, 클라이언트의 접속 및 RPC 서비스 호출에 대해 지속적으로 대기하는 리스너 구동의 진입점입니다. -### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../examples/grpcentity/client.go)) +### 5.2 gRPC 클라이언트 구현 분석 ([client.go](../lib/grpcentity/client.go)) * **원격 서비스 클라이언트 기동 (`NewIoTServiceClient`)**: ```go @@ -276,7 +276,7 @@ protoc --go_out=. --go-grpc_out=. protoapi.proto ### 6.1 `bind: address already in use` (네트워크 소켓 포트 충돌) * **발생 원인**: gRPC 서버 기동 시 설정한 통신 포트 `:8080`이 이미 다른 네트워크 프로세스나 이전 실습 서버의 비정상 종료 등으로 인해 점유되어 바인딩에 실패한 상태입니다. * **조치 방법**: - - `examples/main.go`의 `port` 변수 및 [server.go](../examples/grpcentity/server.go)의 `port` 전역 변수값을 동시에 다른 유휴 포트(예: `:9090`)로 변경하여 구동을 시도합니다. + - `lib/main.go`의 `port` 변수 및 [server.go](../lib/grpcentity/server.go)의 `port` 전역 변수값을 동시에 다른 유휴 포트(예: `:9090`)로 변경하여 구동을 시도합니다. - **🚨 소스코드 설계 제약**: `server.go`에 기재된 `ServerRun(addr string)` 함수는 메인 환경으로부터 주입받은 `addr` 인자값을 사용하지 않고, 패키지 내부 전역 변수인 `port` (하드코딩된 값 `:8080`)를 소켓 리슨 파라미터로 직접 참조하도록 되어 있습니다. 따라서 바인딩 충돌 회피를 위해서는 `main.go`뿐만 아니라 반드시 `server.go` 파일 내부의 전역 변수인 `port` 역시 함께 갱신해 주어야 실제 바인딩 포트 변경이 유효하게 처리됩니다. --- @@ -324,7 +324,7 @@ message DownloadRequest { ``` * **설계 포인트**: `stream` 키워드가 들어간 위치에 주목합니다. `UploadFile`은 입력에 `stream`이 붙어 클라이언트 스트리밍을, `DownloadFile`은 반환(returns)에 `stream`이 붙어 서버 스트리밍 채널을 개설합니다. -### 7.2 서버 저장 및 송수신 구현 ([server.go](../examples/grpcentity/server.go)) +### 7.2 서버 저장 및 송수신 구현 ([server.go](../lib/grpcentity/server.go)) 인메모리 파일 저장소(`fileStore`)를 구현하고 목록 조회(`ListFiles`) 및 서버 다운로드 스트리밍(`DownloadFile`) 핸들러를 정의합니다: ```go @@ -392,7 +392,7 @@ func (IoTServer) DownloadFile(r *protoapi.DownloadRequest, stream protoapi.IoTSe * **목록 조회**: 동시 접근 보호(Race condition 방지)를 위해 읽기 전용 락(`RLock`)을 획득한 후 인메모리 맵을 순회하며 메타데이터 구조체 목록을 집계해 반환합니다. * **파일 다운로드**: 대상 파일 쿼리 실패 시 gRPC 표준 에러(`codes.NotFound`)를 반환합니다. 검증 통과 시 루프 내에서 가상 윈도우 슬라이싱을 집행해 청크 구조체를 구성하고, `stream.Send()`로 직렬화 패킷을 클라이언트 버퍼 큐에 기입합니다. -### 7.3 클라이언트 송수신 기동 ([client.go](../examples/grpcentity/client.go)) +### 7.3 클라이언트 송수신 기동 ([client.go](../lib/grpcentity/client.go)) 클라이언트는 업로드에 성공한 뒤, 서버에 파일 목록 조회를 요구하고, 다운로드 스트림을 개설해 조각 데이터를 재조립하여 무결성을 검사합니다. ```go @@ -435,7 +435,7 @@ func AskDownloadFile(ctx context.Context, m protoapi.IoTServiceClient, fileName 본 기초 실습을 끝마치셨다면, 아래 과제를 해결해보세요: -1. **약속 스펙 확장해 보기**: [protoapi.proto](../examples/grpcentity/protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다. +1. **약속 스펙 확장해 보기**: [protoapi.proto](../lib/grpcentity/protoapi.proto) 파일에 새로운 환경 데이터(예: 미세먼지 수치 `double Dust = 4;`)를 슬쩍 얹어본 뒤, 직접 번역기를 새로 돌리고 Go 소스코드를 고치며 확장해 봅니다. 2. **proto 명세서 물리 분할하기 (실전 모듈화)**: 현재 단일 파일로 구성된 `protoapi.proto`를 기능 성격에 맞춰 `iot_service.proto`(Unary 제어 메시지)와 `file_transfer.proto`(스트리밍 전송 메시지) 2개의 파일로 쪼개어 구성해 봅니다. 이때 두 파일의 `option go_package` 공유 방식과 번역기(`protoc`) 명령어를 다중 타겟(또는 `*.proto`)으로 조율하여 정상 빌드해 보세요. --- diff --git a/docs/HTTP.md b/docs/HTTP.md index 83b15be..146fd69 100644 --- a/docs/HTTP.md +++ b/docs/HTTP.md @@ -27,9 +27,9 @@ Go 진영에서 대표적으로 사랑받는 웹 프레임워크 중 하나로, --- -## 3. 실습 코드 분석 (`examples/httpentity/server.go`) +## 3. 실습 코드 분석 (`lib/httpentity/server.go`) -저장소의 [server.go](../examples/httpentity/server.go) 파일에는 Gin 라우터를 구성하고 API 서버와 정적 웹 서빙을 혼합하여 라우팅을 우회 처리하는 설계 패턴이 주석 상태로 존재합니다. +저장소의 [server.go](../lib/httpentity/server.go) 파일에는 Gin 라우터를 구성하고 API 서버와 정적 웹 서빙을 혼합하여 라우팅을 우회 처리하는 설계 패턴이 주석 상태로 존재합니다. ### 3.1 라우터 엔진 분리 및 통합 핸들링 ```go diff --git a/docs/JSON.md b/docs/JSON.md index e27d2ad..3500e79 100644 --- a/docs/JSON.md +++ b/docs/JSON.md @@ -21,9 +21,9 @@ Go 구조체로 JSON 데이터를 다룰 때 핵심적인 과정입니다. --- -## 2. 실습 코드 분석 (`examples/jsonexample/json_parser.go`) +## 2. 실습 코드 분석 (`lib/jsonexample/json_parser.go`) -저장소의 [json_parser.go](../examples/jsonexample/json_parser.go) 파일은 (1) `map[string]interface{}`와의 직렬화 및 (2) 구조체(`Person`)를 이용한 매핑 방식을 모두 다룹니다. +저장소의 [json_parser.go](../lib/jsonexample/json_parser.go) 파일은 (1) `map[string]interface{}`와의 직렬화 및 (2) 구조체(`Person`)를 이용한 매핑 방식을 모두 다룹니다. ### 2.1 구조체 태그(Struct Tag) 정의 ```go diff --git a/examples/grpcentity/README.md b/lib/grpcentity/README.md similarity index 83% rename from examples/grpcentity/README.md rename to lib/grpcentity/README.md index 983a79d..aa317c9 100644 --- a/examples/grpcentity/README.md +++ b/lib/grpcentity/README.md @@ -1,4 +1,4 @@ -# examples/grpcentity 실습 설명서 +# lib/grpcentity 실습 설명서 본 디렉토리는 Go 언어를 활용한 gRPC 서버 및 클라이언트 실습 예제를 포함하고 있습니다. @@ -16,11 +16,11 @@ ## 🚀 빠른 실행 방법 -이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다. +이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다. -1. 리포지토리 루트의 `examples/main.go`를 엽니다. +1. 리포지토리 루트의 `lib/main.go`를 엽니다. 2. `main()` 함수 내에서 `grpcSample()`의 주석을 해제합니다. 3. 리포지토리 루트에서 다음 명령어를 실행합니다: ```bash - go run ./examples + go run ./lib ``` \ No newline at end of file diff --git a/examples/grpcentity/client.go b/lib/grpcentity/client.go similarity index 99% rename from examples/grpcentity/client.go rename to lib/grpcentity/client.go index 26cf782..13cfe6d 100644 --- a/examples/grpcentity/client.go +++ b/lib/grpcentity/client.go @@ -3,7 +3,7 @@ package entity import ( "context" "fmt" - "grpccanary/examples/grpcentity/protoapi" + "grpccanary/lib/grpcentity/protoapi" "io" "math/rand" "time" diff --git a/examples/grpcentity/protoapi.proto b/lib/grpcentity/protoapi.proto similarity index 100% rename from examples/grpcentity/protoapi.proto rename to lib/grpcentity/protoapi.proto diff --git a/examples/grpcentity/protoapi/protoapi.pb.go b/lib/grpcentity/protoapi/protoapi.pb.go similarity index 100% rename from examples/grpcentity/protoapi/protoapi.pb.go rename to lib/grpcentity/protoapi/protoapi.pb.go diff --git a/examples/grpcentity/protoapi/protoapi_grpc.pb.go b/lib/grpcentity/protoapi/protoapi_grpc.pb.go similarity index 100% rename from examples/grpcentity/protoapi/protoapi_grpc.pb.go rename to lib/grpcentity/protoapi/protoapi_grpc.pb.go diff --git a/examples/grpcentity/server.go b/lib/grpcentity/server.go similarity index 99% rename from examples/grpcentity/server.go rename to lib/grpcentity/server.go index c8d8771..9274665 100644 --- a/examples/grpcentity/server.go +++ b/lib/grpcentity/server.go @@ -3,7 +3,7 @@ package entity import ( "context" "fmt" - "grpccanary/examples/grpcentity/protoapi" + "grpccanary/lib/grpcentity/protoapi" "io" "math/rand" "net" diff --git a/examples/httpentity/README.md b/lib/httpentity/README.md similarity index 82% rename from examples/httpentity/README.md rename to lib/httpentity/README.md index 4544f6a..7d26dd4 100644 --- a/examples/httpentity/README.md +++ b/lib/httpentity/README.md @@ -1,4 +1,4 @@ -# examples/httpentity 실습 설명서 +# lib/httpentity 실습 설명서 본 디렉토리는 Go 언어 웹 프레임워크인 Gin(`gin-gonic`)을 활용한 HTTP 웹 API 서버 실습 예제를 포함하고 있습니다. @@ -15,11 +15,11 @@ ## 🚀 빠른 실행 방법 -이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다. +이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다. -1. 리포지토리 루트의 `examples/main.go`를 엽니다. +1. 리포지토리 루트 of `lib/main.go`를 엽니다. 2. `main()` 함수 내에서 `httpentity` API 호출 주석을 해제합니다. (현재 주석 상태로, 추후 구현 완성을 위한 예제 뼈대 파일입니다.) 3. 리포지토리 루트에서 다음 명령어를 실행합니다: ```bash - go run ./examples + go run ./lib ``` diff --git a/examples/httpentity/client.go b/lib/httpentity/client.go similarity index 100% rename from examples/httpentity/client.go rename to lib/httpentity/client.go diff --git a/examples/httpentity/server.go b/lib/httpentity/server.go similarity index 100% rename from examples/httpentity/server.go rename to lib/httpentity/server.go diff --git a/examples/jsonexample/README.md b/lib/jsonexample/README.md similarity index 81% rename from examples/jsonexample/README.md rename to lib/jsonexample/README.md index 8ded243..d457c6c 100644 --- a/examples/jsonexample/README.md +++ b/lib/jsonexample/README.md @@ -1,4 +1,4 @@ -# examples/jsonexample 실습 설명서 +# lib/jsonexample 실습 설명서 본 디렉토리는 Go 언어 표준 라이브러리(`encoding/json`)를 활용한 JSON 데이터 직렬화 및 역직렬화 실습 예제를 포함하고 있습니다. @@ -15,11 +15,11 @@ ## 🚀 빠른 실행 방법 -이 예제는 리포지토리 루트의 `examples/main.go`를 통해 실행됩니다. +이 예제는 리포지토리 루트의 `lib/main.go`를 통해 실행됩니다. -1. 리포지토리 루트의 `examples/main.go`를 엽니다. +1. 리포지토리 루트의 `lib/main.go`를 엽니다. 2. `main()` 함수 내에서 `jsonexample.JsonParsingExample()`의 주석을 해제합니다. 3. 리포지토리 루트에서 다음 명령어를 실행합니다: ```bash - go run ./examples + go run ./lib ``` diff --git a/examples/jsonexample/json_parser.go b/lib/jsonexample/json_parser.go similarity index 100% rename from examples/jsonexample/json_parser.go rename to lib/jsonexample/json_parser.go diff --git a/examples/main.go b/lib/main.go similarity index 90% rename from examples/main.go rename to lib/main.go index a4fcdbb..d0054ad 100644 --- a/examples/main.go +++ b/lib/main.go @@ -2,8 +2,8 @@ package main import ( "fmt" - entity "grpccanary/examples/grpcentity" - "grpccanary/examples/jsonexample" + entity "grpccanary/lib/grpcentity" + "grpccanary/lib/jsonexample" "time" ) diff --git a/project_analysis_report.md b/project_analysis_report.md index da18df7..87173d1 100644 --- a/project_analysis_report.md +++ b/project_analysis_report.md @@ -22,7 +22,7 @@ grpccanary/ │ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go) │ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc) ├── obj.json # JSON 예제용 샘플 데이터 파일 -├── examples/ +├── lib/ │ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨) │ ├── jsonexample/ │ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제 @@ -50,16 +50,16 @@ grpccanary/ ## 3. 핵심 구성 요소 (학습용 Go 코드) -### 3.1 진입점 — `examples/main.go` +### 3.1 진입점 — `lib/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` +### 3.2 JSON 파싱 예제 — `lib/jsonexample/json_parser.go` - `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다. - 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다. -### 3.3 HTTP 서버 예제 — `examples/httpentity/` +### 3.3 HTTP 서버 예제 — `lib/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) 상태로 보입니다. @@ -72,21 +72,21 @@ grpccanary/ - `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` +### 3.5 gRPC 서버 구현 — `lib/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` +### 3.6 gRPC 클라이언트 구현 — `lib/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` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다. +- **`lib/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다. - **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다. --- @@ -101,7 +101,7 @@ grpccanary/ - **`.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` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음). +**참고**: 새로 추가된 `.gitignore`는 `.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `lib/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음). --- @@ -117,16 +117,16 @@ go mod download # 의존성 다운로드 ```bash go run ./examples ``` -`examples/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다. +`lib/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다. ### 5.3 gRPC 예제 실행 (수동 편집 필요) -1. `examples/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경. +1. `lib/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` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능). +4. 포트 충돌 시(`bind: address already in use`) `lib/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능). ### 5.4 HTTP 예제 `httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다. @@ -137,13 +137,13 @@ go run ./examples 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` 참고). +사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `lib/grpcentity/README.md` 참고). --- ## 6. 주요 관찰 사항 및 특이점 -1. **단일 진입점, 수동 전환 방식**: `examples/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다. +1. **단일 진입점, 수동 전환 방식**: `lib/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 ./...`는 통과합니다.