feat(data-ana): docker 本地测试通过 + gRPC 修复 + nextstep 上下游依赖文档
This commit is contained in:
@@ -320,7 +320,7 @@
|
||||
### 2.6 data-ana(Python/FastAPI,P4)
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 学情诊断 | ClickHouse 宽表查询,5s 内返回 |
|
||||
| CDC 链路 | Debezium 监听 MySQL binlog → Kafka(`edu-cdc.next_edu_cloud.<table>`)→ DataAna 消费写 ClickHouse |
|
||||
| CDC 延迟监控 | Debezium 暴露 lag metrics,超阈值告警 |
|
||||
@@ -360,6 +360,12 @@
|
||||
| ruff per-file-ignores | gRPC servicer 方法必须 PascalCase(N802 忽略)/ FastAPI Depends 在参数默认值(B008 忽略),pyproject.toml 配 per-file-ignores |
|
||||
| Mock 数据脚本 | `scripts/data-ana-mock-data.sql` 提供 5 宽表演示数据(20 学生×2 考试×3 知识点),用 `now()-INTERVAL` 避免硬编码日期 |
|
||||
| Python 3.12+ 现代化 | ruff UP042 用 StrEnum 替代 `str, Enum` / UP046 用 PEP 695 类型参数 `class Foo[T]` 替代 `Generic[T]` |
|
||||
| ClickHouse argMax 别名冲突 | `argMax(col, calculated_at)` 与同 SELECT 的 `max(calculated_at) AS calculated_at` 冲突(ILLEGAL_AGGREGATION),别名改为 `latest_calculated_at` |
|
||||
| Python proto 生成 | `grpc_tools.protoc` 生成 `_pb2_grpc.py` 用 `import xxx_pb2`(flat),放入 package 需改为 `from generated_proto import xxx_pb2` |
|
||||
| Dockerfile PYTHONPATH | Python 服务 `src/generated_proto/` 作为包导入时,Dockerfile 需 `ENV PYTHONPATH="/app/src"`,否则 `ModuleNotFoundError: generated_proto` |
|
||||
| OTel 日志噪声 | OTel collector 不可达时刷屏 `Transient error ... retrying`,设 `OTEL_TRACES_EXPORTER=none` + `OTEL_METRICS_EXPORTER=none` + `OTEL_LOGS_EXPORTER=none` 静默 |
|
||||
| Docker Hub 不可达 | Dockerfile base image 用标准名 `python:3.12-slim`,本地 `docker pull docker.m.daocloud.io/library/python:3.12-slim` 后 `docker tag` 为标准名 |
|
||||
| ruff per-file-ignores | 自动生成的 proto 代码(`src/generated_proto/*.py`)在 `pyproject.toml` 配 `per-file-ignores = ["ALL"]`,避免 lint-staged 传单文件时 `extend-exclude` 无效 |
|
||||
|
||||
### 2.7 messaging(TS/NestJS,P5)
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ COPY --from=builder /app/.venv /app/.venv
|
||||
|
||||
# 确保虚拟环境在 PATH 中
|
||||
ENV PATH="/app/.venv/bin:$PATH"
|
||||
ENV PYTHONPATH="/app/src"
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
|
||||
282
services/data-ana/docs/nextstep.md
Normal file
282
services/data-ana/docs/nextstep.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# data-ana 模块上下游依赖与工作清单(Next Steps)
|
||||
|
||||
> 模块:data-ana(智能洞察域,数据分析服务)
|
||||
> 负责人:ai11
|
||||
> 更新日期:2026-07-13
|
||||
> 关联文档:[01-understanding.md](./01-understanding.md)、[02-architecture-design.md](./02-architecture-design.md)、[data-ana_contract.md](../../../docs/architecture/issues/contracts/data-ana_contract.md)、[data-ana_workline.md](../../../docs/architecture/issues/worklines/data-ana_workline.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 模块当前状态
|
||||
|
||||
data-ana 已完成 P2-P5 全部代码实现,P6 硬化期未开始。当前服务包含:
|
||||
|
||||
- **HTTP 14 端点**(3 基础 + 11 业务),端口 3006
|
||||
- **gRPC 12 RPC**(11 unary + 1 server-streaming),端口 50055
|
||||
- **CDC 消费者**:Debezium binlog → ClickHouse 5 宽表,手动 commit + Redis 去重
|
||||
- **ClickHouse 宽表**:student_dashboard_view / student_errors / mastery_snapshot / ai_usage_log / attendance_logs
|
||||
- **Kafka 生产者**:MasteryEvent + WarningTriggered(Outbox 豁免)
|
||||
- **iam gRPC 集成**:GetEffectiveDataScope + Redis 缓存 + role 降级兜底
|
||||
- **降级模式**:ClickHouse/Kafka/Redis/iam 任一不可达时服务仍可启动
|
||||
|
||||
---
|
||||
|
||||
## 2. 上游依赖(data-ana 依赖谁)
|
||||
|
||||
### 2.1 iam 服务(ai06 负责)— P0
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | ------------------------------------------- | ------------------------------------------------------------------ | ----------------------------- |
|
||||
| 1 | gRPC `GetEffectiveDataScope(userId)` :50052 | DataScope 6 级过滤(SELF/CLASS/GRADE/SCHOOL/DISTRICT/ALL) | ✅ 已就绪(iam.proto 已补全) |
|
||||
| 2 | REST `GET /healthz` :3002 | /readyz 下游健康检查 | ⏳ 待 iam 容器启动 |
|
||||
| 3 | JWT RS256 公钥 | (data-ana 不直接验签,由 api-gateway 验签后注入 x-user-* header) | — |
|
||||
|
||||
**环境变量**:`DATA_ANA_IAM_GRPC_TARGET=iam:50052`
|
||||
**降级策略**:iam 不可达时按 role 映射默认 DataScope + `degraded: true`
|
||||
|
||||
### 2.2 ClickHouse(基础设施)— P0
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | ---------------- | ------------------------------ | -------------------------------------- |
|
||||
| 1 | ClickHouse :8123 | 5 宽表读写(分析查询核心存储) | ✅ Docker 已启动 |
|
||||
| 2 | DDL 建表 | 5 宽表 schema | ✅ 已创建 `scripts/clickhouse_ddl.sql` |
|
||||
| 3 | 种子数据 | mock 数据集 | ✅ 已创建 `scripts/seed_clickhouse.py` |
|
||||
|
||||
**环境变量**:`DATA_ANA_CLICKHOUSE_HOST=clickhouse`、`DATA_ANA_CLICKHOUSE_PORT=8123`、`DATA_ANA_CLICKHOUSE_DATABASE=edu_analytics`
|
||||
**降级策略**:ClickHouse 不可达时服务启动跳过,查询返回 degraded 空数据
|
||||
|
||||
### 2.3 Kafka(基础设施)— P1
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | ----------------- | ----------------------------------------------------------- | ---------------- |
|
||||
| 1 | Kafka :29092 消费 | CDC topic(edu-cdc.next_edu_cloud.* 等 7 topic) | ✅ Docker 已启动 |
|
||||
| 2 | Kafka :29092 生产 | edu.insight.mastery.updated + edu.insight.warning.triggered | ✅ Docker 已启动 |
|
||||
|
||||
**环境变量**:`DATA_ANA_KAFKA_BROKERS=kafka:29092`
|
||||
**降级策略**:Kafka 不可达时 CDC 消费者不启动,事件发布静默失败
|
||||
|
||||
### 2.4 Redis(基础设施)— P1
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | ----------- | ------------------------------------------------------------------- | ---------------- |
|
||||
| 1 | Redis :6379 | DataScope 缓存(5min TTL)+ CDC event_id 去重 + Warning bitmap 去重 | ✅ Docker 已启动 |
|
||||
|
||||
**环境变量**:`DATA_ANA_REDIS_URL=redis://redis:6379`
|
||||
**降级策略**:Redis 不可达时跳过缓存,每次直查 iam gRPC
|
||||
|
||||
### 2.5 core-edu 服务(ai07 负责)— P1(CDC 依赖)
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | --------------------------- | ------------------------------------------------------ | ------------------------- |
|
||||
| 1 | MySQL binlog(core_edu 库) | CDC 消费 grades/exams/homework/attendance/classes 变更 | ⏳ 待 core-edu MySQL 就绪 |
|
||||
| 2 | Debezium Connect | MySQL → Kafka CDC 管道 | ⏳ 待 Debezium 部署 |
|
||||
|
||||
### 2.6 content 服务(ai08 负责)— P2(CDC 依赖)
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | -------------------------- | --------------------------------------------------------- | ------------------------ |
|
||||
| 1 | MySQL binlog(content 库) | CDC 消费 content_knowledge_points 变更 → Redis 知识点缓存 | ⏳ 待 content MySQL 就绪 |
|
||||
|
||||
### 2.7 ai 服务(ai12 负责)— P2(事件消费)
|
||||
|
||||
| # | 依赖项 | 用途 | 状态 |
|
||||
| --- | ---------------------------------- | ------------------------------------- | ----------------------------------- |
|
||||
| 1 | Kafka topic `edu.insight.ai.usage` | 消费 AIUsageEvent → ai_usage_log 宽表 | ✅ events.proto 已补全 AIUsageEvent |
|
||||
|
||||
---
|
||||
|
||||
## 3. 下游依赖(谁依赖 data-ana)
|
||||
|
||||
### 3.1 teacher-bff(ai03 负责)— P0
|
||||
|
||||
| # | gRPC RPC | 用途 | 状态 |
|
||||
| --- | ------------------------------------- | ---------------------------- | --------- |
|
||||
| 1 | `GetStudentWeakness(classId)` :50055 | `studentWeakness` 查询 | ✅ 已实现 |
|
||||
| 2 | `GetLearningTrend(classId)` :50055 | `learningTrend` 查询 | ✅ 已实现 |
|
||||
| 3 | `GetClassPerformance(classId)` :50055 | `classPerformance` 查询 | ✅ 已实现 |
|
||||
| 4 | `GetAdminDashboard(input)` :50055 | `adminDashboard` AI 用量区块 | ✅ 已实现 |
|
||||
|
||||
**需求来源**:[teacher-bff nextstep.md](../../teacher-bff/docs/nextstep.md) §2.4
|
||||
**环境变量**(teacher-bff 侧):`DATA_ANA_GRPC_TARGET=data-ana:50055`
|
||||
|
||||
### 3.2 student-bff(ai04 负责)— P0
|
||||
|
||||
| # | gRPC RPC | 用途 | 状态 |
|
||||
| --- | -------------------------------------------------- | ----------------------- | --------- |
|
||||
| 1 | `GetStudentWeakness(studentId)` :50055 | `myWeakness` 查询 | ✅ 已实现 |
|
||||
| 2 | `GetLearningTrend(studentId)` :50055 | `myTrend` 查询 | ✅ 已实现 |
|
||||
| 3 | `GetStudentMastery(studentId)` :50055 | `myMasterySummary` 查询 | ✅ 已实现 |
|
||||
| 4 | `GetStudentDashboard(studentId)` :50055 | `studentDashboard` 查询 | ✅ 已实现 |
|
||||
| 5 | `GetMasteryDistribution(classId)` :50055 | 班级掌握度分布 | ✅ 已实现 |
|
||||
| 6 | HTTP `GET /analytics/student/{id}/errorbook` :3006 | `myErrorBook` 查询 | ✅ 已实现 |
|
||||
|
||||
**需求来源**:[student-bff nextstep.md](../../student-bff/docs/nextstep.md) §3.4
|
||||
**说明**:student-bff nextstep.md 中列出的 `GetStudentGrowth`/`GetAssignmentAnalysis`/`ListDiagnosticReports`/`ListErrorBookItems`/`ListPracticeSessionsByStudent`/`StartPracticeSession`/`SubmitPracticeAnswer` 等 RPC 在 analytics.proto 中未定义,data-ana 通过现有 12 RPC + HTTP 端点覆盖这些需求。
|
||||
|
||||
### 3.3 parent-bff(ai05 负责)— P1
|
||||
|
||||
| # | gRPC RPC | 用途 | 状态 |
|
||||
| --- | -------------------------------------- | ------------------------------- | --------- |
|
||||
| 1 | `GetStudentWeakness(studentId)` :50055 | `childWeakness` 查询 | ✅ 已实现 |
|
||||
| 2 | `GetLearningTrend(studentId)` :50055 | `childTrend` 查询 | ✅ 已实现 |
|
||||
| 3 | `GetClassPerformance(classId)` :50055 | `classRank`/`classAverage` 计算 | ✅ 已实现 |
|
||||
|
||||
**需求来源**:[parent-bff nextstep.md](../../parent-bff/docs/nextstep.md) §4.3
|
||||
**说明**:parent-bff nextstep.md 中列出的 `childGrowthArchive`/`childLearningPath`/`childErrorBookStats`/`childTopWrongQuestions`/`childWeakKps`/`childMasterySummary`/`childDiagnosticReports`/`childPracticeStats`/`childPracticeSessions` 等查询在当前 RPC 中未直接覆盖,parent-bff 通过降级模式返回空数据。data-ana 可通过 HTTP 端点 `/analytics/student/{id}/errorbook` 等补充覆盖。
|
||||
|
||||
### 3.4 api-gateway(ai01 负责)— P0
|
||||
|
||||
| # | 路由 | 用途 | 状态 |
|
||||
| --- | ------------------------------------- | ---------------------- | --------------------- |
|
||||
| 1 | `/api/v1/analytics/*` → data-ana:3006 | data-ana HTTP 端点代理 | ✅ api-gateway 已配置 |
|
||||
| 2 | `/api/v1/dashboard/*` → data-ana:3006 | 仪表盘代理 | ✅ api-gateway 已配置 |
|
||||
|
||||
**需求来源**:[api-gateway nextstep.md](../../api-gateway/docs/nextstep.md) §5.2
|
||||
|
||||
---
|
||||
|
||||
## 4. Docker 本地测试
|
||||
|
||||
### 4.1 镜像构建
|
||||
|
||||
```bash
|
||||
# 在仓库根目录执行(Docker Hub 不可达时先 docker pull + docker tag python:3.12-slim)
|
||||
docker build -t edu/data-ana:test -f services/data-ana/Dockerfile services/data-ana/
|
||||
```
|
||||
|
||||
### 4.2 容器启动(接入 edu-full_default 网络)
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name edu-data-ana-test \
|
||||
--network edu-full_default \
|
||||
-p 3006:3006 -p 50055:50055 \
|
||||
-e DATA_ANA_CLICKHOUSE_HOST=clickhouse \
|
||||
-e DATA_ANA_CLICKHOUSE_PORT=8123 \
|
||||
-e DATA_ANA_CLICKHOUSE_DATABASE=edu_analytics \
|
||||
-e DATA_ANA_KAFKA_BROKERS=kafka:29092 \
|
||||
-e DATA_ANA_REDIS_URL=redis://redis:6379 \
|
||||
-e DATA_ANA_DEV_MODE=true \
|
||||
-e OTEL_TRACES_EXPORTER=none \
|
||||
-e OTEL_METRICS_EXPORTER=none \
|
||||
-e OTEL_LOGS_EXPORTER=none \
|
||||
edu/data-ana:test
|
||||
```
|
||||
|
||||
### 4.3 健康检查验证
|
||||
|
||||
```bash
|
||||
# liveness
|
||||
curl http://localhost:3006/healthz
|
||||
|
||||
# readiness(下游不可达时返回 degraded)
|
||||
curl http://localhost:3006/readyz
|
||||
```
|
||||
|
||||
### 4.4 ClickHouse DDL + 种子数据
|
||||
|
||||
```bash
|
||||
# 建表
|
||||
docker exec edu-clickhouse clickhouse-client --password clickhouse --multiquery < services/data-ana/scripts/clickhouse_ddl.sql
|
||||
|
||||
# 种子数据(需安装 clickhouse-connect)
|
||||
cd services/data-ana && python scripts/seed_clickhouse.py
|
||||
```
|
||||
|
||||
### 4.5 测试结果(2026-07-13 已通过)
|
||||
|
||||
| # | 测试项 | 结果 | 说明 |
|
||||
| --- | ------------------------------------------- | ---- | ------------------------------------------------------------------- |
|
||||
| 1 | Docker 镜像构建 | ✅ | `edu/data-ana:test` 构建成功 |
|
||||
| 2 | 容器启动 + 健康检查 | ✅ | `/healthz` 200 OK, `/readyz` ready=true |
|
||||
| 3 | ClickHouse 5 表 DDL | ✅ | 4 ReplacingMergeTree + 1 MergeTree |
|
||||
| 4 | 种子数据写入 | ✅ | student_dashboard_view(8) + student_errors(3) + mastery_snapshot(6) |
|
||||
| 5 | HTTP `/analytics/student/stu-001/weakness` | ✅ | 返回 2 个薄弱知识点(kp-math-002 mastery=0.35/0.45) |
|
||||
| 6 | HTTP `/analytics/student/dashboard` | ✅ | 返回 8 条学情记录 + 薄弱点 + 趋势 + 掌握度 |
|
||||
| 7 | HTTP `/analytics/student/stu-001/trend` | ✅ | 返回 8 个趋势点 |
|
||||
| 8 | HTTP `/analytics/student/stu-001/errorbook` | ✅ | 返回 3 条错题记录 |
|
||||
| 9 | HTTP `/analytics/student/stu-001/mastery` | ✅ | 返回 4 个知识点掌握度,overallMastery=0.6875 |
|
||||
| 10 | gRPC `GetStudentWeakness` :50055 | ✅ | 返回 2 个 weak_points |
|
||||
| 11 | gRPC `GetStudentMastery` :50055 | ✅ | 返回 4 个 knowledge_points,overall_mastery=0.6875 |
|
||||
| 12 | gRPC `GetLearningTrend` :50055 | ✅ | 返回 8 个 trend points |
|
||||
| 13 | ruff lint | ✅ | 零错误 |
|
||||
|
||||
**降级说明**:iam gRPC 未配置(`not_configured`),HTTP 响应标记 `degraded: true` + `degraded_reason: iam_grpc_unavailable_fallback`,但 ClickHouse 真实数据正常返回。班级级查询(`class/performance`、`class/mastery-distribution`)因 DataScope 校验降级返回空数据,iam 就绪后自动恢复。
|
||||
|
||||
---
|
||||
|
||||
## 5. 环境变量清单(Docker 部署)
|
||||
|
||||
| 变量 | 必填 | 示例值 | 说明 |
|
||||
| ------------------------------ | ---- | -------------------- | -------------------------------------- |
|
||||
| `DATA_ANA_HTTP_PORT` | 是 | `3006` | HTTP 监听端口 |
|
||||
| `DATA_ANA_GRPC_PORT` | 是 | `50055` | gRPC 监听端口 |
|
||||
| `DATA_ANA_DEV_MODE` | 否 | `true`/`false` | 开发模式(跳过部分校验) |
|
||||
| `DATA_ANA_CLICKHOUSE_HOST` | 是 | `clickhouse` | ClickHouse 主机 |
|
||||
| `DATA_ANA_CLICKHOUSE_PORT` | 否 | `8123` | ClickHouse HTTP 端口 |
|
||||
| `DATA_ANA_CLICKHOUSE_DATABASE` | 否 | `edu_analytics` | ClickHouse 数据库 |
|
||||
| `DATA_ANA_KAFKA_BROKERS` | 是 | `kafka:29092` | Kafka broker 地址 |
|
||||
| `DATA_ANA_REDIS_URL` | 是 | `redis://redis:6379` | Redis 连接地址 |
|
||||
| `DATA_ANA_IAM_GRPC_TARGET` | 是 | `iam:50052` | iam gRPC 目标 |
|
||||
| `OTEL_TRACES_EXPORTER` | 否 | `none` | 禁用 OTel traces(collector 不可达时) |
|
||||
|
||||
---
|
||||
|
||||
## 6. 剩余工作
|
||||
|
||||
### 6.1 Docker 本地测试(已完成 2026-07-13)
|
||||
|
||||
| # | 工作项 | 状态 |
|
||||
| --- | ------------------------------ | --------- |
|
||||
| 1 | Docker 镜像构建 | ✅ 已通过 |
|
||||
| 2 | ClickHouse 容器启动 + DDL 建表 | ✅ 已通过 |
|
||||
| 3 | 种子数据写入 | ✅ 已通过 |
|
||||
| 4 | data-ana 容器启动 + 健康检查 | ✅ 已通过 |
|
||||
| 5 | HTTP 端点测试(无 mock 数据) | ✅ 已通过 |
|
||||
| 6 | gRPC 端点测试 | ✅ 已通过 |
|
||||
|
||||
### 6.2 P6 硬化任务
|
||||
|
||||
| # | 工作项 | 状态 |
|
||||
| --- | ------------------------------------ | --------- |
|
||||
| 1 | CDC 多实例水平扩展 | ⏳ 未开始 |
|
||||
| 2 | ExamCache Redis 化 | ⏳ 未开始 |
|
||||
| 3 | 容量规划 + TTL 归档策略 | ⏳ 未开始 |
|
||||
| 4 | 监控告警完善(Prometheus + Grafana) | ⏳ 未开始 |
|
||||
| 5 | readyz 深度硬化(超时控制) | ⏳ 未开始 |
|
||||
|
||||
### 6.3 端到端联调
|
||||
|
||||
| # | 工作项 | 阻塞条件 | 状态 |
|
||||
| --- | --------------------- | ------------------------------------- | ---- |
|
||||
| 1 | teacher-bff gRPC 联调 | teacher-bff 配置 DATA_ANA_GRPC_TARGET | ⏳ |
|
||||
| 2 | student-bff gRPC 联调 | student-bff 配置 DATA_ANA_GRPC_TARGET | ⏳ |
|
||||
| 3 | parent-bff gRPC 联调 | parent-bff 配置 DATA_ANA_GRPC_TARGET | ⏳ |
|
||||
| 4 | CDC 通道联调 | core-edu MySQL + Debezium 就绪 | ⏳ |
|
||||
| 5 | AIUsageEvent 消费联调 | ai 服务发布事件 | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键文件路径
|
||||
|
||||
| 文件 | 用途 |
|
||||
| -------------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| `services/data-ana/src/data_ana/main.py` | HTTP 14 端点 + lifespan(gRPC + CDC 启动) |
|
||||
| `services/data-ana/src/data_ana/grpc_server.py` | gRPC 12 RPC(含 server-streaming) |
|
||||
| `services/data-ana/src/data_ana/cdc_consumer.py` | CDC 消费者(5 表 + AIUsageEvent) |
|
||||
| `services/data-ana/src/data_ana/analytics_service.py` | 4 端 Dashboard + DataScope 注入 |
|
||||
| `services/data-ana/src/data_ana/mastery_service.py` | 掌握度算法(加权滑动平均 + 遗忘曲线) |
|
||||
| `services/data-ana/src/data_ana/warning_service.py` | 5 类预警 + Redis 去重 |
|
||||
| `services/data-ana/src/data_ana/config.py` | 全配置项(DATA_ANA_ 前缀) |
|
||||
| `services/data-ana/src/data_ana/repository/clickhouse_repository.py` | ClickHouse 查询(FINAL/argMax 去重) |
|
||||
| `services/data-ana/src/data_ana/repository/iam_client.py` | iam gRPC + Redis 缓存 + 降级 |
|
||||
| `services/data-ana/src/data_ana/repository/kafka_producer.py` | Kafka 事件发布(idempotent) |
|
||||
| `services/data-ana/src/generated_proto/` | Python protobuf 生成代码(analytics/iam/events) |
|
||||
| `services/data-ana/scripts/clickhouse_ddl.sql` | 5 宽表建表脚本 |
|
||||
| `services/data-ana/scripts/seed_clickhouse.py` | 种子数据脚本 |
|
||||
| `services/data-ana/Dockerfile` | 多阶段构建(python:3.12-slim) |
|
||||
| `packages/shared-proto/proto/analytics.proto` | gRPC 12 RPC 契约 |
|
||||
|
||||
---
|
||||
|
||||
**本文件由 ai11 维护。data-ana 已完成 P2-P5 全部代码实现 + Docker 本地测试通过(无 mock 数据,真实 ClickHouse 查询)。等待 iam 容器就绪后即可端到端联调。**
|
||||
@@ -38,3 +38,5 @@ select = ["E", "F", "I", "N", "W", "UP", "B", "SIM"]
|
||||
"src/data_ana/grpc_server.py" = ["N802"]
|
||||
# FastAPI 标准模式:Depends/Query 在参数默认值中调用,B008 不适用
|
||||
"src/data_ana/main.py" = ["B008"]
|
||||
# 自动生成的 protobuf 代码,不做任何 lint 校验
|
||||
"src/generated_proto/*.py" = ["ALL"]
|
||||
|
||||
@@ -508,6 +508,7 @@ async def start_grpc_server() -> Any | None:
|
||||
|
||||
try:
|
||||
import grpc # type: ignore[import-not-found]
|
||||
|
||||
from generated_proto import analytics_pb2_grpc # type: ignore[import-not-found]
|
||||
except ImportError as exc:
|
||||
logger.warning("grpc_dependencies_not_installed_degraded", error=str(exc))
|
||||
|
||||
@@ -291,13 +291,14 @@ async def query_mastery_snapshot(student_id: str, subject_id: str = "") -> dict
|
||||
where_clause = " AND ".join(where_parts)
|
||||
try:
|
||||
# argMax 获取每个 knowledge_point_id 的最新 mastery_level
|
||||
# 注意:别名不能与 argMax 的第二个参数名相同,否则 ClickHouse 将别名解析为聚合函数
|
||||
result = await asyncio.to_thread(
|
||||
client.query,
|
||||
f"SELECT "
|
||||
f" knowledge_point_id, "
|
||||
f" argMax(mastery_level, calculated_at) AS mastery_level, "
|
||||
f" argMax(subject_id, calculated_at) AS subject_id, "
|
||||
f" max(calculated_at) AS calculated_at "
|
||||
f" max(calculated_at) AS latest_calculated_at "
|
||||
f"FROM mastery_snapshot "
|
||||
f"WHERE {where_clause} "
|
||||
f"GROUP BY knowledge_point_id "
|
||||
|
||||
@@ -45,6 +45,7 @@ async def _init_grpc() -> tuple[Any, Any] | None:
|
||||
_grpc_initialized = True
|
||||
try:
|
||||
import grpc # type: ignore[import-not-found]
|
||||
|
||||
from generated_proto import iam_pb2_grpc # type: ignore[import-not-found]
|
||||
|
||||
_grpc_channel = grpc.aio.insecure_channel(
|
||||
|
||||
0
services/data-ana/src/generated_proto/__init__.py
Normal file
0
services/data-ana/src/generated_proto/__init__.py
Normal file
99
services/data-ana/src/generated_proto/analytics_pb2.py
Normal file
99
services/data-ana/src/generated_proto/analytics_pb2.py
Normal file
File diff suppressed because one or more lines are too long
632
services/data-ana/src/generated_proto/analytics_pb2_grpc.py
Normal file
632
services/data-ana/src/generated_proto/analytics_pb2_grpc.py
Normal file
@@ -0,0 +1,632 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
from generated_proto import analytics_pb2 as analytics__pb2
|
||||
|
||||
GRPC_GENERATED_VERSION = "1.82.1"
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f"The grpc package installed is at version {GRPC_VERSION},"
|
||||
+ " but the generated code in analytics_pb2_grpc.py depends on"
|
||||
+ f" grpcio>={GRPC_GENERATED_VERSION}."
|
||||
+ f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}"
|
||||
+ f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}."
|
||||
)
|
||||
|
||||
|
||||
class AnalyticsServiceStub:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.GetClassPerformance = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetClassPerformance",
|
||||
request_serializer=analytics__pb2.GetClassPerformanceRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.ClassPerformance.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetStudentWeakness = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentWeakness",
|
||||
request_serializer=analytics__pb2.GetStudentWeaknessRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentWeakness.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetLearningTrend = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetLearningTrend",
|
||||
request_serializer=analytics__pb2.GetLearningTrendRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.LearningTrend.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetTeacherDashboard = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetTeacherDashboard",
|
||||
request_serializer=analytics__pb2.GetTeacherDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.TeacherDashboard.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetStudentDashboard = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentDashboard",
|
||||
request_serializer=analytics__pb2.GetStudentDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentDashboard.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetParentDashboard = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetParentDashboard",
|
||||
request_serializer=analytics__pb2.GetParentDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.ParentDashboard.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetAdminDashboard = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetAdminDashboard",
|
||||
request_serializer=analytics__pb2.GetAdminDashboardRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.AdminDashboard.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetWarnings = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetWarnings",
|
||||
request_serializer=analytics__pb2.GetWarningsRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.WarningList.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.TriggerWarning = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/TriggerWarning",
|
||||
request_serializer=analytics__pb2.TriggerWarningRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.TriggerWarningResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetMasteryDistribution = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetMasteryDistribution",
|
||||
request_serializer=analytics__pb2.GetMasteryDistributionRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.MasteryDistribution.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetStudentMastery = channel.unary_unary(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentMastery",
|
||||
request_serializer=analytics__pb2.GetStudentMasteryRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.StudentMastery.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.SubscribeMasteryUpdate = channel.unary_stream(
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/SubscribeMasteryUpdate",
|
||||
request_serializer=analytics__pb2.SubscribeMasteryUpdateRequest.SerializeToString,
|
||||
response_deserializer=analytics__pb2.MasteryUpdateEvent.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
|
||||
class AnalyticsServiceServicer:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
def GetClassPerformance(self, request, context):
|
||||
"""班级成绩分析(平均分/及格率/参考人数)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetStudentWeakness(self, request, context):
|
||||
"""学生薄弱知识点(mastery_level < 0.6)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetLearningTrend(self, request, context):
|
||||
"""学习趋势(历史成绩曲线)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetTeacherDashboard(self, request, context):
|
||||
"""教师仪表盘聚合(班级概览 + 待办 + 预警)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetStudentDashboard(self, request, context):
|
||||
"""学生仪表盘(个人学情 + 排名 + 薄弱点)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetParentDashboard(self, request, context):
|
||||
"""家长仪表盘(孩子学情概览)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetAdminDashboard(self, request, context):
|
||||
"""管理员仪表盘(全校统计 + AI 用量)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetWarnings(self, request, context):
|
||||
"""预警列表查询(按班级/严重度/时间过滤)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def TriggerWarning(self, request, context):
|
||||
"""手动触发预警(管理员/教师主动标记关注)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetMasteryDistribution(self, request, context):
|
||||
"""班级掌握度分布(mastered/progressing/weak 三档)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetStudentMastery(self, request, context):
|
||||
"""学生知识点掌握度明细."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def SubscribeMasteryUpdate(self, request, context):
|
||||
"""订阅掌握度更新(server-streaming,P5+ AI 个性化推荐实时推送通道)."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
|
||||
def add_AnalyticsServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
"GetClassPerformance": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetClassPerformance,
|
||||
request_deserializer=analytics__pb2.GetClassPerformanceRequest.FromString,
|
||||
response_serializer=analytics__pb2.ClassPerformance.SerializeToString,
|
||||
),
|
||||
"GetStudentWeakness": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentWeakness,
|
||||
request_deserializer=analytics__pb2.GetStudentWeaknessRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentWeakness.SerializeToString,
|
||||
),
|
||||
"GetLearningTrend": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetLearningTrend,
|
||||
request_deserializer=analytics__pb2.GetLearningTrendRequest.FromString,
|
||||
response_serializer=analytics__pb2.LearningTrend.SerializeToString,
|
||||
),
|
||||
"GetTeacherDashboard": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetTeacherDashboard,
|
||||
request_deserializer=analytics__pb2.GetTeacherDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.TeacherDashboard.SerializeToString,
|
||||
),
|
||||
"GetStudentDashboard": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentDashboard,
|
||||
request_deserializer=analytics__pb2.GetStudentDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentDashboard.SerializeToString,
|
||||
),
|
||||
"GetParentDashboard": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetParentDashboard,
|
||||
request_deserializer=analytics__pb2.GetParentDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.ParentDashboard.SerializeToString,
|
||||
),
|
||||
"GetAdminDashboard": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetAdminDashboard,
|
||||
request_deserializer=analytics__pb2.GetAdminDashboardRequest.FromString,
|
||||
response_serializer=analytics__pb2.AdminDashboard.SerializeToString,
|
||||
),
|
||||
"GetWarnings": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetWarnings,
|
||||
request_deserializer=analytics__pb2.GetWarningsRequest.FromString,
|
||||
response_serializer=analytics__pb2.WarningList.SerializeToString,
|
||||
),
|
||||
"TriggerWarning": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.TriggerWarning,
|
||||
request_deserializer=analytics__pb2.TriggerWarningRequest.FromString,
|
||||
response_serializer=analytics__pb2.TriggerWarningResponse.SerializeToString,
|
||||
),
|
||||
"GetMasteryDistribution": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetMasteryDistribution,
|
||||
request_deserializer=analytics__pb2.GetMasteryDistributionRequest.FromString,
|
||||
response_serializer=analytics__pb2.MasteryDistribution.SerializeToString,
|
||||
),
|
||||
"GetStudentMastery": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetStudentMastery,
|
||||
request_deserializer=analytics__pb2.GetStudentMasteryRequest.FromString,
|
||||
response_serializer=analytics__pb2.StudentMastery.SerializeToString,
|
||||
),
|
||||
"SubscribeMasteryUpdate": grpc.unary_stream_rpc_method_handler(
|
||||
servicer.SubscribeMasteryUpdate,
|
||||
request_deserializer=analytics__pb2.SubscribeMasteryUpdateRequest.FromString,
|
||||
response_serializer=analytics__pb2.MasteryUpdateEvent.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"next_edu_cloud.analytics.v1.AnalyticsService", rpc_method_handlers
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers(
|
||||
"next_edu_cloud.analytics.v1.AnalyticsService", rpc_method_handlers
|
||||
)
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class AnalyticsService:
|
||||
"""AnalyticsService 数据分析服务契约(D6 智能洞察领域).
|
||||
P4 启用 gRPC server 端口 50055,HTTP 3006 保留作 Gateway 直连降级.
|
||||
所有 RPC 返回 ActionState 信封(success/data/error/details.degraded).
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def GetClassPerformance(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetClassPerformance",
|
||||
analytics__pb2.GetClassPerformanceRequest.SerializeToString,
|
||||
analytics__pb2.ClassPerformance.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentWeakness(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentWeakness",
|
||||
analytics__pb2.GetStudentWeaknessRequest.SerializeToString,
|
||||
analytics__pb2.StudentWeakness.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetLearningTrend(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetLearningTrend",
|
||||
analytics__pb2.GetLearningTrendRequest.SerializeToString,
|
||||
analytics__pb2.LearningTrend.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetTeacherDashboard(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetTeacherDashboard",
|
||||
analytics__pb2.GetTeacherDashboardRequest.SerializeToString,
|
||||
analytics__pb2.TeacherDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentDashboard(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentDashboard",
|
||||
analytics__pb2.GetStudentDashboardRequest.SerializeToString,
|
||||
analytics__pb2.StudentDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetParentDashboard(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetParentDashboard",
|
||||
analytics__pb2.GetParentDashboardRequest.SerializeToString,
|
||||
analytics__pb2.ParentDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetAdminDashboard(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetAdminDashboard",
|
||||
analytics__pb2.GetAdminDashboardRequest.SerializeToString,
|
||||
analytics__pb2.AdminDashboard.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetWarnings(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetWarnings",
|
||||
analytics__pb2.GetWarningsRequest.SerializeToString,
|
||||
analytics__pb2.WarningList.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def TriggerWarning(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/TriggerWarning",
|
||||
analytics__pb2.TriggerWarningRequest.SerializeToString,
|
||||
analytics__pb2.TriggerWarningResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetMasteryDistribution(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetMasteryDistribution",
|
||||
analytics__pb2.GetMasteryDistributionRequest.SerializeToString,
|
||||
analytics__pb2.MasteryDistribution.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetStudentMastery(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/GetStudentMastery",
|
||||
analytics__pb2.GetStudentMasteryRequest.SerializeToString,
|
||||
analytics__pb2.StudentMastery.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def SubscribeMasteryUpdate(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_stream(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.analytics.v1.AnalyticsService/SubscribeMasteryUpdate",
|
||||
analytics__pb2.SubscribeMasteryUpdateRequest.SerializeToString,
|
||||
analytics__pb2.MasteryUpdateEvent.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
97
services/data-ana/src/generated_proto/events_pb2.py
Normal file
97
services/data-ana/src/generated_proto/events_pb2.py
Normal file
File diff suppressed because one or more lines are too long
26
services/data-ana/src/generated_proto/events_pb2_grpc.py
Normal file
26
services/data-ana/src/generated_proto/events_pb2_grpc.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
|
||||
GRPC_GENERATED_VERSION = "1.82.1"
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f"The grpc package installed is at version {GRPC_VERSION},"
|
||||
+ " but the generated code in events_pb2_grpc.py depends on"
|
||||
+ f" grpcio>={GRPC_GENERATED_VERSION}."
|
||||
+ f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}"
|
||||
+ f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}."
|
||||
)
|
||||
93
services/data-ana/src/generated_proto/iam_pb2.py
Normal file
93
services/data-ana/src/generated_proto/iam_pb2.py
Normal file
File diff suppressed because one or more lines are too long
778
services/data-ana/src/generated_proto/iam_pb2_grpc.py
Normal file
778
services/data-ana/src/generated_proto/iam_pb2_grpc.py
Normal file
@@ -0,0 +1,778 @@
|
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
|
||||
import grpc
|
||||
import warnings
|
||||
|
||||
from generated_proto import iam_pb2 as iam__pb2
|
||||
|
||||
GRPC_GENERATED_VERSION = "1.82.1"
|
||||
GRPC_VERSION = grpc.__version__
|
||||
_version_not_supported = False
|
||||
|
||||
try:
|
||||
from grpc._utilities import first_version_is_lower
|
||||
|
||||
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||
except ImportError:
|
||||
_version_not_supported = True
|
||||
|
||||
if _version_not_supported:
|
||||
raise RuntimeError(
|
||||
f"The grpc package installed is at version {GRPC_VERSION},"
|
||||
+ " but the generated code in iam_pb2_grpc.py depends on"
|
||||
+ f" grpcio>={GRPC_GENERATED_VERSION}."
|
||||
+ f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}"
|
||||
+ f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}."
|
||||
)
|
||||
|
||||
|
||||
class IamServiceStub:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.Register = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/Register",
|
||||
request_serializer=iam__pb2.RegisterRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.AuthResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.Login = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/Login",
|
||||
request_serializer=iam__pb2.LoginRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.AuthResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.RefreshToken = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/RefreshToken",
|
||||
request_serializer=iam__pb2.RefreshTokenRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.TokenPair.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.Logout = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/Logout",
|
||||
request_serializer=iam__pb2.LogoutRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.LogoutResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetUserInfo = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetUserInfo",
|
||||
request_serializer=iam__pb2.GetUserInfoRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetUserProfile = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetUserProfile",
|
||||
request_serializer=iam__pb2.GetUserProfileRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.UpdateProfile = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/UpdateProfile",
|
||||
request_serializer=iam__pb2.UpdateProfileRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.UserInfo.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.ChangePassword = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/ChangePassword",
|
||||
request_serializer=iam__pb2.ChangePasswordRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ChangePasswordResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.BatchGetUsers = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/BatchGetUsers",
|
||||
request_serializer=iam__pb2.BatchGetUsersRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.BatchGetUsersResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetEffectivePermissions = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectivePermissions",
|
||||
request_serializer=iam__pb2.GetEffectivePermissionsRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectivePermissionsResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetEffectiveAccess = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectiveAccess",
|
||||
request_serializer=iam__pb2.GetEffectiveAccessRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectiveAccessResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetEffectiveDataScope = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectiveDataScope",
|
||||
request_serializer=iam__pb2.GetEffectiveDataScopeRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.EffectiveDataScope.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetViewports = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetViewports",
|
||||
request_serializer=iam__pb2.GetViewportsRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ViewportsResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetPublicKey = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetPublicKey",
|
||||
request_serializer=iam__pb2.GetPublicKeyRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.PublicKeyResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
self.GetChildrenByParent = channel.unary_unary(
|
||||
"/next_edu_cloud.iam.v1.IamService/GetChildrenByParent",
|
||||
request_serializer=iam__pb2.GetChildrenByParentRequest.SerializeToString,
|
||||
response_deserializer=iam__pb2.ChildrenResponse.FromString,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
|
||||
class IamServiceServicer:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
def Register(self, request, context):
|
||||
"""认证类"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def Login(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def RefreshToken(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def Logout(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetUserInfo(self, request, context):
|
||||
"""用户信息类"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetUserProfile(self, request, context):
|
||||
"""GetUserProfile 是 GetUserInfo 的语义别名(student-bff 期望的命名).
|
||||
返回结构与 GetUserInfo 完全相同,仅 RPC 名不同以兼容下游契约.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def UpdateProfile(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def ChangePassword(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def BatchGetUsers(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetEffectivePermissions(self, request, context):
|
||||
"""权限与视口类"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetEffectiveAccess(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetEffectiveDataScope(self, request, context):
|
||||
"""GetEffectiveDataScope 解析用户可见数据范围(DataScope 6 级).
|
||||
data-ana gRPC 调用此 RPC 解析查询过滤范围(coord-cross-review §2 #3 裁决 P4 补全).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetViewports(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetPublicKey(self, request, context):
|
||||
"""密钥与关系类"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
def GetChildrenByParent(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details("Method not implemented!")
|
||||
raise NotImplementedError("Method not implemented!")
|
||||
|
||||
|
||||
def add_IamServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
"Register": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Register,
|
||||
request_deserializer=iam__pb2.RegisterRequest.FromString,
|
||||
response_serializer=iam__pb2.AuthResponse.SerializeToString,
|
||||
),
|
||||
"Login": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Login,
|
||||
request_deserializer=iam__pb2.LoginRequest.FromString,
|
||||
response_serializer=iam__pb2.AuthResponse.SerializeToString,
|
||||
),
|
||||
"RefreshToken": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.RefreshToken,
|
||||
request_deserializer=iam__pb2.RefreshTokenRequest.FromString,
|
||||
response_serializer=iam__pb2.TokenPair.SerializeToString,
|
||||
),
|
||||
"Logout": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.Logout,
|
||||
request_deserializer=iam__pb2.LogoutRequest.FromString,
|
||||
response_serializer=iam__pb2.LogoutResponse.SerializeToString,
|
||||
),
|
||||
"GetUserInfo": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetUserInfo,
|
||||
request_deserializer=iam__pb2.GetUserInfoRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
"GetUserProfile": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetUserProfile,
|
||||
request_deserializer=iam__pb2.GetUserProfileRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
"UpdateProfile": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateProfile,
|
||||
request_deserializer=iam__pb2.UpdateProfileRequest.FromString,
|
||||
response_serializer=iam__pb2.UserInfo.SerializeToString,
|
||||
),
|
||||
"ChangePassword": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ChangePassword,
|
||||
request_deserializer=iam__pb2.ChangePasswordRequest.FromString,
|
||||
response_serializer=iam__pb2.ChangePasswordResponse.SerializeToString,
|
||||
),
|
||||
"BatchGetUsers": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.BatchGetUsers,
|
||||
request_deserializer=iam__pb2.BatchGetUsersRequest.FromString,
|
||||
response_serializer=iam__pb2.BatchGetUsersResponse.SerializeToString,
|
||||
),
|
||||
"GetEffectivePermissions": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectivePermissions,
|
||||
request_deserializer=iam__pb2.GetEffectivePermissionsRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectivePermissionsResponse.SerializeToString,
|
||||
),
|
||||
"GetEffectiveAccess": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectiveAccess,
|
||||
request_deserializer=iam__pb2.GetEffectiveAccessRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectiveAccessResponse.SerializeToString,
|
||||
),
|
||||
"GetEffectiveDataScope": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetEffectiveDataScope,
|
||||
request_deserializer=iam__pb2.GetEffectiveDataScopeRequest.FromString,
|
||||
response_serializer=iam__pb2.EffectiveDataScope.SerializeToString,
|
||||
),
|
||||
"GetViewports": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetViewports,
|
||||
request_deserializer=iam__pb2.GetViewportsRequest.FromString,
|
||||
response_serializer=iam__pb2.ViewportsResponse.SerializeToString,
|
||||
),
|
||||
"GetPublicKey": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetPublicKey,
|
||||
request_deserializer=iam__pb2.GetPublicKeyRequest.FromString,
|
||||
response_serializer=iam__pb2.PublicKeyResponse.SerializeToString,
|
||||
),
|
||||
"GetChildrenByParent": grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetChildrenByParent,
|
||||
request_deserializer=iam__pb2.GetChildrenByParentRequest.FromString,
|
||||
response_serializer=iam__pb2.ChildrenResponse.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
"next_edu_cloud.iam.v1.IamService", rpc_method_handlers
|
||||
)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers("next_edu_cloud.iam.v1.IamService", rpc_method_handlers)
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class IamService:
|
||||
"""IamService 定义身份与访问管理契约
|
||||
双入口策略(president §2.16):REST 供 gateway 透传 + admin-portal 直连,
|
||||
gRPC 供 BFF 聚合调用。同一 Application Service 同时被两种 Controller 调用。
|
||||
gRPC 端口 50052,P2 即启用(I1 裁决)。
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def Register(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/Register",
|
||||
iam__pb2.RegisterRequest.SerializeToString,
|
||||
iam__pb2.AuthResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def Login(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/Login",
|
||||
iam__pb2.LoginRequest.SerializeToString,
|
||||
iam__pb2.AuthResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def RefreshToken(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/RefreshToken",
|
||||
iam__pb2.RefreshTokenRequest.SerializeToString,
|
||||
iam__pb2.TokenPair.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def Logout(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/Logout",
|
||||
iam__pb2.LogoutRequest.SerializeToString,
|
||||
iam__pb2.LogoutResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetUserInfo(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetUserInfo",
|
||||
iam__pb2.GetUserInfoRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetUserProfile(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetUserProfile",
|
||||
iam__pb2.GetUserProfileRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def UpdateProfile(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/UpdateProfile",
|
||||
iam__pb2.UpdateProfileRequest.SerializeToString,
|
||||
iam__pb2.UserInfo.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def ChangePassword(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/ChangePassword",
|
||||
iam__pb2.ChangePasswordRequest.SerializeToString,
|
||||
iam__pb2.ChangePasswordResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def BatchGetUsers(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/BatchGetUsers",
|
||||
iam__pb2.BatchGetUsersRequest.SerializeToString,
|
||||
iam__pb2.BatchGetUsersResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectivePermissions(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectivePermissions",
|
||||
iam__pb2.GetEffectivePermissionsRequest.SerializeToString,
|
||||
iam__pb2.EffectivePermissionsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectiveAccess(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectiveAccess",
|
||||
iam__pb2.GetEffectiveAccessRequest.SerializeToString,
|
||||
iam__pb2.EffectiveAccessResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetEffectiveDataScope(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetEffectiveDataScope",
|
||||
iam__pb2.GetEffectiveDataScopeRequest.SerializeToString,
|
||||
iam__pb2.EffectiveDataScope.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetViewports(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetViewports",
|
||||
iam__pb2.GetViewportsRequest.SerializeToString,
|
||||
iam__pb2.ViewportsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetPublicKey(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetPublicKey",
|
||||
iam__pb2.GetPublicKeyRequest.SerializeToString,
|
||||
iam__pb2.PublicKeyResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def GetChildrenByParent(
|
||||
request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None,
|
||||
):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
"/next_edu_cloud.iam.v1.IamService/GetChildrenByParent",
|
||||
iam__pb2.GetChildrenByParentRequest.SerializeToString,
|
||||
iam__pb2.ChildrenResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True,
|
||||
)
|
||||
Reference in New Issue
Block a user