token.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. package controller
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "time"
  8. "github.com/bytedance/sonic"
  9. "github.com/gin-gonic/gin"
  10. "github.com/labring/sealos/service/aiproxy/common/network"
  11. "github.com/labring/sealos/service/aiproxy/common/random"
  12. "github.com/labring/sealos/service/aiproxy/middleware"
  13. "github.com/labring/sealos/service/aiproxy/model"
  14. )
  15. // TokenResponse represents the response structure for token endpoints
  16. type TokenResponse struct {
  17. *model.Token
  18. AccessedAt time.Time `json:"accessed_at"`
  19. }
  20. func (t *TokenResponse) MarshalJSON() ([]byte, error) {
  21. type Alias TokenResponse
  22. return sonic.Marshal(&struct {
  23. *Alias
  24. CreatedAt int64 `json:"created_at"`
  25. ExpiredAt int64 `json:"expired_at"`
  26. AccessedAt int64 `json:"accessed_at"`
  27. }{
  28. Alias: (*Alias)(t),
  29. CreatedAt: t.CreatedAt.UnixMilli(),
  30. ExpiredAt: t.ExpiredAt.UnixMilli(),
  31. AccessedAt: t.AccessedAt.UnixMilli(),
  32. })
  33. }
  34. type (
  35. AddTokenRequest struct {
  36. Name string `json:"name"`
  37. Subnets []string `json:"subnets"`
  38. Models []string `json:"models"`
  39. ExpiredAt int64 `json:"expiredAt"`
  40. Quota float64 `json:"quota"`
  41. }
  42. UpdateTokenStatusRequest struct {
  43. Status int `json:"status"`
  44. }
  45. UpdateTokenNameRequest struct {
  46. Name string `json:"name"`
  47. }
  48. )
  49. func (at *AddTokenRequest) ToToken() *model.Token {
  50. var expiredAt time.Time
  51. if at.ExpiredAt > 0 {
  52. expiredAt = time.UnixMilli(at.ExpiredAt)
  53. }
  54. return &model.Token{
  55. Name: model.EmptyNullString(at.Name),
  56. Subnets: at.Subnets,
  57. Models: at.Models,
  58. ExpiredAt: expiredAt,
  59. Quota: at.Quota,
  60. }
  61. }
  62. func validateToken(token AddTokenRequest) error {
  63. if token.Name == "" {
  64. return errors.New("token name cannot be empty")
  65. }
  66. if len(token.Name) > 30 {
  67. return errors.New("token name is too long")
  68. }
  69. if err := network.IsValidSubnets(token.Subnets); err != nil {
  70. return fmt.Errorf("invalid subnet: %w", err)
  71. }
  72. return nil
  73. }
  74. func validateTokenUpdate(token AddTokenRequest) error {
  75. if err := network.IsValidSubnets(token.Subnets); err != nil {
  76. return fmt.Errorf("invalid subnet: %w", err)
  77. }
  78. return nil
  79. }
  80. func buildTokenResponse(token *model.Token) *TokenResponse {
  81. lastRequestAt, _ := model.GetTokenLastRequestTime(token.ID)
  82. return &TokenResponse{
  83. Token: token,
  84. AccessedAt: lastRequestAt,
  85. }
  86. }
  87. func buildTokenResponses(tokens []*model.Token) []*TokenResponse {
  88. responses := make([]*TokenResponse, len(tokens))
  89. for i, token := range tokens {
  90. responses[i] = buildTokenResponse(token)
  91. }
  92. return responses
  93. }
  94. // Token list handlers
  95. func GetTokens(c *gin.Context) {
  96. page, perPage := parsePageParams(c)
  97. group := c.Query("group")
  98. order := c.Query("order")
  99. status, _ := strconv.Atoi(c.Query("status"))
  100. tokens, total, err := model.GetTokens(group, page, perPage, order, status)
  101. if err != nil {
  102. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  103. return
  104. }
  105. middleware.SuccessResponse(c, gin.H{
  106. "tokens": buildTokenResponses(tokens),
  107. "total": total,
  108. })
  109. }
  110. func GetGroupTokens(c *gin.Context) {
  111. group := c.Param("group")
  112. if group == "" {
  113. middleware.ErrorResponse(c, http.StatusOK, "group is required")
  114. return
  115. }
  116. page, perPage := parsePageParams(c)
  117. order := c.Query("order")
  118. status, _ := strconv.Atoi(c.Query("status"))
  119. tokens, total, err := model.GetTokens(group, page, perPage, order, status)
  120. if err != nil {
  121. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  122. return
  123. }
  124. middleware.SuccessResponse(c, gin.H{
  125. "tokens": buildTokenResponses(tokens),
  126. "total": total,
  127. })
  128. }
  129. func SearchTokens(c *gin.Context) {
  130. page, perPage := parsePageParams(c)
  131. keyword := c.Query("keyword")
  132. order := c.Query("order")
  133. name := c.Query("name")
  134. key := c.Query("key")
  135. status, _ := strconv.Atoi(c.Query("status"))
  136. group := c.Query("group")
  137. tokens, total, err := model.SearchTokens(group, keyword, page, perPage, order, status, name, key)
  138. if err != nil {
  139. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  140. return
  141. }
  142. middleware.SuccessResponse(c, gin.H{
  143. "tokens": buildTokenResponses(tokens),
  144. "total": total,
  145. })
  146. }
  147. func SearchGroupTokens(c *gin.Context) {
  148. group := c.Param("group")
  149. if group == "" {
  150. middleware.ErrorResponse(c, http.StatusOK, "group is required")
  151. return
  152. }
  153. page, perPage := parsePageParams(c)
  154. keyword := c.Query("keyword")
  155. order := c.Query("order")
  156. name := c.Query("name")
  157. key := c.Query("key")
  158. status, _ := strconv.Atoi(c.Query("status"))
  159. tokens, total, err := model.SearchTokens(group, keyword, page, perPage, order, status, name, key)
  160. if err != nil {
  161. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  162. return
  163. }
  164. middleware.SuccessResponse(c, gin.H{
  165. "tokens": buildTokenResponses(tokens),
  166. "total": total,
  167. })
  168. }
  169. // Single token handlers
  170. func GetToken(c *gin.Context) {
  171. id, err := strconv.Atoi(c.Param("id"))
  172. if err != nil {
  173. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  174. return
  175. }
  176. token, err := model.GetTokenByID(id)
  177. if err != nil {
  178. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  179. return
  180. }
  181. middleware.SuccessResponse(c, buildTokenResponse(token))
  182. }
  183. func GetGroupToken(c *gin.Context) {
  184. group := c.Param("group")
  185. if group == "" {
  186. middleware.ErrorResponse(c, http.StatusOK, "group is required")
  187. return
  188. }
  189. id, err := strconv.Atoi(c.Param("id"))
  190. if err != nil {
  191. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  192. return
  193. }
  194. token, err := model.GetGroupTokenByID(group, id)
  195. if err != nil {
  196. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  197. return
  198. }
  199. middleware.SuccessResponse(c, buildTokenResponse(token))
  200. }
  201. func AddGroupToken(c *gin.Context) {
  202. group := c.Param("group")
  203. var req AddTokenRequest
  204. if err := c.ShouldBindJSON(&req); err != nil {
  205. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  206. return
  207. }
  208. if err := validateToken(req); err != nil {
  209. middleware.ErrorResponse(c, http.StatusOK, "parameter error: "+err.Error())
  210. return
  211. }
  212. token := req.ToToken()
  213. token.GroupID = group
  214. token.Key = random.GenerateKey()
  215. if err := model.InsertToken(token, c.Query("auto_create_group") == "true"); err != nil {
  216. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  217. return
  218. }
  219. middleware.SuccessResponse(c, &TokenResponse{Token: token})
  220. }
  221. // Delete handlers
  222. func DeleteToken(c *gin.Context) {
  223. id, err := strconv.Atoi(c.Param("id"))
  224. if err != nil {
  225. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  226. return
  227. }
  228. if err := model.DeleteTokenByID(id); err != nil {
  229. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  230. return
  231. }
  232. middleware.SuccessResponse(c, nil)
  233. }
  234. func DeleteTokens(c *gin.Context) {
  235. var ids []int
  236. if err := c.ShouldBindJSON(&ids); err != nil {
  237. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  238. return
  239. }
  240. if err := model.DeleteTokensByIDs(ids); err != nil {
  241. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  242. return
  243. }
  244. middleware.SuccessResponse(c, nil)
  245. }
  246. func DeleteGroupToken(c *gin.Context) {
  247. group := c.Param("group")
  248. id, err := strconv.Atoi(c.Param("id"))
  249. if err != nil {
  250. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  251. return
  252. }
  253. if err := model.DeleteGroupTokenByID(group, id); err != nil {
  254. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  255. return
  256. }
  257. middleware.SuccessResponse(c, nil)
  258. }
  259. func DeleteGroupTokens(c *gin.Context) {
  260. group := c.Param("group")
  261. var ids []int
  262. if err := c.ShouldBindJSON(&ids); err != nil {
  263. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  264. return
  265. }
  266. if err := model.DeleteGroupTokensByIDs(group, ids); err != nil {
  267. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  268. return
  269. }
  270. middleware.SuccessResponse(c, nil)
  271. }
  272. // Update handlers
  273. func UpdateToken(c *gin.Context) {
  274. id, err := strconv.Atoi(c.Param("id"))
  275. if err != nil {
  276. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  277. return
  278. }
  279. var req AddTokenRequest
  280. if err := c.ShouldBindJSON(&req); err != nil {
  281. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  282. return
  283. }
  284. if err := validateTokenUpdate(req); err != nil {
  285. middleware.ErrorResponse(c, http.StatusOK, "parameter error: "+err.Error())
  286. return
  287. }
  288. token := req.ToToken()
  289. if err := model.UpdateToken(id, token); err != nil {
  290. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  291. return
  292. }
  293. middleware.SuccessResponse(c, &TokenResponse{Token: token})
  294. }
  295. func UpdateGroupToken(c *gin.Context) {
  296. group := c.Param("group")
  297. id, err := strconv.Atoi(c.Param("id"))
  298. if err != nil {
  299. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  300. return
  301. }
  302. var req AddTokenRequest
  303. if err := c.ShouldBindJSON(&req); err != nil {
  304. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  305. return
  306. }
  307. if err := validateTokenUpdate(req); err != nil {
  308. middleware.ErrorResponse(c, http.StatusOK, "parameter error: "+err.Error())
  309. return
  310. }
  311. token := req.ToToken()
  312. if err := model.UpdateGroupToken(id, group, token); err != nil {
  313. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  314. return
  315. }
  316. middleware.SuccessResponse(c, &TokenResponse{Token: token})
  317. }
  318. func UpdateTokenStatus(c *gin.Context) {
  319. id, err := strconv.Atoi(c.Param("id"))
  320. if err != nil {
  321. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  322. return
  323. }
  324. var req UpdateTokenStatusRequest
  325. if err := c.ShouldBindJSON(&req); err != nil {
  326. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  327. return
  328. }
  329. if err := model.UpdateTokenStatus(id, req.Status); err != nil {
  330. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  331. return
  332. }
  333. middleware.SuccessResponse(c, nil)
  334. }
  335. func UpdateGroupTokenStatus(c *gin.Context) {
  336. group := c.Param("group")
  337. id, err := strconv.Atoi(c.Param("id"))
  338. if err != nil {
  339. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  340. return
  341. }
  342. var req UpdateTokenStatusRequest
  343. if err := c.ShouldBindJSON(&req); err != nil {
  344. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  345. return
  346. }
  347. if err := model.UpdateGroupTokenStatus(group, id, req.Status); err != nil {
  348. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  349. return
  350. }
  351. middleware.SuccessResponse(c, nil)
  352. }
  353. func UpdateTokenName(c *gin.Context) {
  354. id, err := strconv.Atoi(c.Param("id"))
  355. if err != nil {
  356. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  357. return
  358. }
  359. var req UpdateTokenNameRequest
  360. if err := c.ShouldBindJSON(&req); err != nil {
  361. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  362. return
  363. }
  364. if err := model.UpdateTokenName(id, req.Name); err != nil {
  365. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  366. return
  367. }
  368. middleware.SuccessResponse(c, nil)
  369. }
  370. func UpdateGroupTokenName(c *gin.Context) {
  371. group := c.Param("group")
  372. id, err := strconv.Atoi(c.Param("id"))
  373. if err != nil {
  374. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  375. return
  376. }
  377. var req UpdateTokenNameRequest
  378. if err := c.ShouldBindJSON(&req); err != nil {
  379. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  380. return
  381. }
  382. if err := model.UpdateGroupTokenName(group, id, req.Name); err != nil {
  383. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  384. return
  385. }
  386. middleware.SuccessResponse(c, nil)
  387. }