feat(instanceMgr): add getInfo endpoint to retrieve instance details

Implement new GET endpoint `/frpcAct/instanceMgr/getInfo` to fetch frpc instance information
Add documentation for the new API endpoint in docs/api.md
The handler returns different information based on user permission level
This commit is contained in:
2026-03-25 22:20:32 +08:00
parent 25f88249c2
commit e83436fe9b
3 changed files with 182 additions and 0 deletions
+96
View File
@@ -972,3 +972,99 @@ func GetInstanceStatusHandler(w http.ResponseWriter, r *http.Request) {
SendSuccessResponse(w, "Instance status retrieved successfully", responseData)
postLog.Info(fmt.Sprintf("[GetInstanceStatusHandler] Retrieved status for instance %d (name: %s), isRunning: %v", instanceID, instance.Name, isRunning))
}
func GetInstanceInfoHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
postLog.Debug(fmt.Sprintf("[GetInstanceInfoHandler] Invalid request method: %s", r.Method))
return
}
queryParams := r.URL.Query()
instanceIDStr := queryParams.Get("instanceID")
if instanceIDStr == "" {
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
instanceID, err := strconv.Atoi(instanceIDStr)
if err != nil {
SendErrorResponse(w, http.StatusBadRequest, "Invalid instanceID format")
return
}
userID, _, err := ValidateRequestWithHeader(w, r)
if err != nil {
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] Failed to validate request header: %v", err))
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
return
}
instance, err := DBQueryFrpcInstanceByID(instanceID)
if err == sql.ErrNoRows {
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] User %d tried to get info of a not existed instance: %d", userID, instanceID))
return
}
if err != nil {
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] Failed to query instance: %v", err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
return
}
if instance.UserID != userID {
SendErrorResponse(w, http.StatusForbidden, "Instance not found")
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] User %d tried to get info of instance %d that does not belong to them", userID, instanceID))
return
}
userType, err := GetUserType(userID)
if err != nil {
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] Failed to get user type: %v", err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
return
}
serviceName, err := GetServiceNameByInstanceID(instanceID)
if err != nil {
postLog.Error(fmt.Sprintf("[GetInstanceInfoHandler] Failed to get service name: %v", err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get service name")
return
}
isRunning := IsInstanceRunning(instanceID)
responseData := map[string]interface{}{
"name": instance.Name,
"serviceName": serviceName,
"createdAt": instance.CreatedAt,
"createdBy": instance.CreatedBy,
"isRunning": isRunning,
"auth_method": "",
"bootAtStart": instance.BootAtStart,
"runUser": instance.RunUser,
"configPath": instance.ConfigPath,
}
configContent, err := os.ReadFile(instance.ConfigPath)
if err == nil {
config, err := decodeFrpcConfig(string(configContent))
if err == nil {
if authMethod, ok := config.Global["auth.method"]; ok {
responseData["auth_method"] = authMethod
}
if userType == "admin" || userType == "superuser" {
if serverAddr, ok := config.Global["serverAddr"]; ok {
responseData["serverAddr"] = serverAddr
}
if serverPort, ok := config.Global["serverPort"]; ok {
responseData["serverPort"] = serverPort
}
}
}
}
SendSuccessResponse(w, "Instance info retrieved successfully", responseData)
postLog.Info(fmt.Sprintf("[GetInstanceInfoHandler] Retrieved info for instance %d (name: %s), userType: %s", instanceID, instance.Name, userType))
}