# Project 2: UE-RM Monitoring Service
## 課程目標
在上一次的 Project 中,我們藉由模擬 FAE 的日常對 5GS 的運作有了一定的掌握。在這次的作業中,你需要扮演 RD 的日常,根據 3GPP 定義的 Technical Specification 來實作對應的服務。
- [ ] 學習閱讀 3GPP TS 文件
- [ ] 學習 SBI 服務開發
- [ ] 了解網路元件如何互動
- [ ] 利用設計模式設計出簡潔有效的程式碼
## 作業說明
使用以下命令取得此次作業的提交樣板:
```sh
$ git clone https://github.com/NYCU-CNDI/amf-rms.git
```
在這次的作業中,你需要按照 [Requirements](#Requirements) 提供的規格書為 AMF 實作一個新的 SBI service。並且在適當的時機通知該 SBI service 的 service consumer。
- 請將修改完的程式碼包含 `.git` 紀錄一起打包,提交至 E3 作業區
- 會有隱藏測資,請確保所有行為符合規格書規範,以及考慮多用戶請求併發的情況
## Requirements
請根據規格書實作 UE-RM Monitoring Service:
- [UE-RM Monitoring Service 規格書](https://hackmd.io/@cndi2025/SyhOHt0sxx)
:::info
補充:
如果對 SBI 仍不熟悉,請參考 https://github.com/free5gc/free5GLabs/blob/master/lab4/README.md 。
:::
```mermaid
flowchart TD
A[AF 發送 POST /subscriptions] --> B[AMF Namf-RMMonitoring<br/>接收訂閱請求]
B --> C[AMF Subscription Table<br/>儲存 Subscription<br/>UE ID、Callback URI、Event]
C --> D[回傳 201 Created<br/>+ SubscriptionID 給 AF]
%% UE 狀態改變事件
E[UE 狀態改變<br/>AMF UE Context / FSM] --> F[AMF Event Handler Hook]
F --> G[查找對應 UE 的<br/>Subscription Table]
G -->|符合事件| H[組成通知 JSON Payload]
H --> I[HTTP POST 通知至 AF Callback URI]
I --> J[AF 收到通知<br/>處理 UE 狀態改變]
%% 流程關聯
subgraph AMF
B
C
F
G
H
I
end
```
### 1. AMF 實作 RM Subscription service
RM Subscription service 是 AMF 提供的功能,Service
AMF 所實作的 RM Subscription service 需要提供 GET/POST/PUT/DELETION 四種方式供 Service Consumer 使用。
#### GET Operation
回傳目前已經存在的 UE-RM subscription。
#### POST Operation
新增一個 UE-RM subscription,相關 schema 如下:
```go
type Subscription struct {
SubId string `json:"subId"` // 由 AMF 產生的 subs id
UeId string `json:"ueId"` // UE SUPI
NotifyUri string `json:"notifyUri"` // 由 service consumer 填入,當訂閱的 UE 的 FSM 發生轉變,會透過 URI 通知 service consumer。
}
```
根據規格書的定義,呼叫 POST API 時需帶入 subscriptionID,請修改 API handler 的行為,使 AMF 能夠:
- 為 Service consumer 請求的 Subscription 分配 SubscriptionID
#### PUT Operation
新增或覆蓋一個 UE-RM subscription,相關 schema 同 **POST Operation**。
#### DELETE Operation
刪除已存在的 UE-RM subscription。
#### Error Handling
對於不合法的 Case,一率回應 Status code 404。
#### 實作說明
SBI server 會在初始化時根據不同的 API group 逐一初始化對應的 http handler,請根據此次作業的規格書提供的內容修改 `getRMSRoutes()` 以滿足作業需求:
```go
func (s *Server) getRMSRoutes() []Route {
return []Route{
{
Name: "root",
Method: http.MethodGet,
Pattern: "/",
APIFunc: func(c *gin.Context) {
c.String(http.StatusOK, "Hello World!")
},
},
// add more Route based on provided spec
}
}
```
### 2. 實作 FSM plugin
#### 實作說明
請實作一個 RSM service,滿足以下介面:
```go
type RMS interface {
HandleEvent(*State, EventType, ArgsType, Transition)
}
```
並且在適當的地方呼叫 `AttachRSM()` 將你實作的 RMS 加載至 `GmmFSM`:
```go
func AttachRSM(rms fsm.RMS) {
GmmFSM.WithRSM(rms)
}
```
RMS 請實作在 `amf/internal/rms/rms.go`。
此外,當 AMF 的 RMS service 需要通知 service consumer 時,請使用 `http.DefaultClient` 發出 POST 請求,並且使用下列 schema 作為 request body:
```go
type UeRMNotif struct {
SubId string `json:"subId"`
UeId string `json:"ueId"`
PrevState string `json:"from"`
CurrState string `json:"to"`
}
```