Implement engine-bridge v2 plugin masquerade (#10)
This commit is contained in:
78
docs/history/2026-04-07_이슈10-engine-bridge-v2-generator.md
Normal file
78
docs/history/2026-04-07_이슈10-engine-bridge-v2-generator.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# 2026-04-07 — Issue #10 engine-bridge v2 Generator
|
||||
|
||||
- 역할: Generator
|
||||
- 계약: `docs/contracts/engine-bridge-v2.md`
|
||||
- 소요 시간: 약 35분 (단일 세션)
|
||||
- Context 사용량: 약 95k tokens (대용량 sln/.cs 디렉터리 스캔 + MetadataLoadContext 출력)
|
||||
|
||||
## Editor03 / HmEG 디스커버리 결과
|
||||
|
||||
`MetadataLoadContext`로 `EG-BIM Modeler/Editor03.PluginInterface.dll`,
|
||||
`Editor07.WidgetPluginInterface.dll`, `HmEG.dll`, `Plugins/EgBoxPlugin/EgBoxPlugin.dll`을
|
||||
메타데이터 전용으로 열어 다음을 확인했다:
|
||||
|
||||
- **실제 plugin 컨트랙트는 `HmEG.IPlugin`** (HmEG.dll). Members:
|
||||
`string Name { get; }`, `EGViewport View { get; set; }`,
|
||||
`bool RethrowException { get; set; }`, `object Run(object[])`.
|
||||
- **MEF Export 어트리뷰트는 사용되지 않는다.** 로딩은 `HmEG.PluginLoader`
|
||||
(`LoadProjectPlugins`/`LoadPlugin(path,name)`)가 직접 수행한다.
|
||||
`EgBoxPlugin.EgBoxPlugin` 샘플도 `[Export]` 없이 단순히
|
||||
`Editor.PluginInterface.EditorPlugin`을 상속한다.
|
||||
- **`Editor.PluginInterface.EditorPlugin`** (Editor03.PluginInterface.dll)
|
||||
은 `HmEG.IPlugin`을 구현하는 추상 base다.
|
||||
abstract 멤버: `Name { get; }`, `Description { get; }`,
|
||||
`protected void Initialize()`. 그 외 `AppManager`, `RootSpace`,
|
||||
`ViewportManager`, `View`, `AddModelToRootSpace(...)` 등의 헬퍼를 노출한다.
|
||||
- **`Editor07.WidgetPluginInterface`** 는 위젯 전용(`WidzetPlugin`,
|
||||
`HmEG_DebugWidzetPlugin`)이며 v2 범위 밖이라 미사용.
|
||||
|
||||
→ 결론: `HmEgBridgePlugin : Editor.PluginInterface.EditorPlugin` 으로
|
||||
구현. `Name`/`Description` override + `protected override Initialize()`,
|
||||
HTTP listener는 생성자에서 안전하게 부팅 (`Initialize`가 호출되지 않더라도
|
||||
listener는 살아있음).
|
||||
|
||||
### 디스커버리 시 주의사항
|
||||
|
||||
- MetadataLoadContext에 `Microsoft.NETCore.App` 런타임 디렉터리만 넣으면
|
||||
`WindowsBase`의 `System.Windows.Markup.InternalTypeHelper`를 못 찾아
|
||||
`TypeLoadException`이 난다. **WindowsDesktop ref pack
|
||||
(`packs/Microsoft.WindowsDesktop.App.Ref/8.0.22/ref/net8.0`)** 도 함께
|
||||
resolver에 등록해야 한다. 동일 파일명은 dedupe 필요.
|
||||
- 같은 이유로 `Editor03.PluginInterface`는 `<UseWPF>true</UseWPF>`인
|
||||
net8.0-windows 프로젝트에서만 빌드된다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `src/Recordingtest.EgPlugin/` (PortResolver, IEngineStateProvider,
|
||||
Null/ReflectionEngineStateProvider, StateRouter, BridgeHttpServer,
|
||||
HmEgBridgePlugin)
|
||||
- `src/Recordingtest.EngineBridge.Client/` (HmEgHttpSnapshot,
|
||||
EngineBridgeException)
|
||||
- `tests/Recordingtest.EngineBridge.IntegrationTests/` (FakeBridgeServer +
|
||||
6 xUnit tests)
|
||||
- `tests/Recordingtest.EgPlugin.Tests/` (5 xUnit tests for StateRouter +
|
||||
PortResolver)
|
||||
- `docs/guides/engine-bridge-deploy.md`
|
||||
|
||||
## 빌드 / 테스트 결과
|
||||
|
||||
- `dotnet build recordingtest.sln` → green (warning 0, error 0)
|
||||
- `dotnet test tests/Recordingtest.EngineBridge.IntegrationTests` → 6/6 통과
|
||||
- `dotnet test tests/Recordingtest.EgPlugin.Tests` → 5/5 통과
|
||||
- 신규 프로젝트 4개를 `recordingtest.sln`에 추가
|
||||
- `EG-BIM Modeler/` 폴더에는 일체 쓰지 않음 (가드 훅 준수). 배포는 가이드
|
||||
문서로만 기술.
|
||||
|
||||
## 리스크 / 후속
|
||||
|
||||
- `ReflectionEngineStateProvider`는 v2 skeleton: 모든 메서드가 안전한
|
||||
default를 반환한다. **HmEG 내부 타입(특히 `HmEGAppManager`,
|
||||
`EGViewport`, 선택/카메라 manager)에 대한 진짜 reflection 매핑은 v3에서
|
||||
smoke test 후 확정해야 한다.** 후보 멤버는
|
||||
`docs/engine-catalog/hmeg-candidates.json` 참고.
|
||||
- `HttpListener` urlacl이 등록 안 된 환경에서는 첫 실행에 관리자 권한 또는
|
||||
`netsh http add urlacl` 필요 — 가이드에 명시.
|
||||
- `Editor.PluginInterface.EditorPlugin.Initialize()`가 protected이고
|
||||
HmEG.PluginLoader가 어느 시점에 호출하는지는 메타데이터로 확인 불가
|
||||
(런타임 동작). 그래서 listener를 생성자에서 부팅했다. PluginLoader가
|
||||
생성자 호출만으로 충분한지는 smoke test에서 확인 필요.
|
||||
Reference in New Issue
Block a user