dashboard_api.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // Copyright 2017 fatedier, fatedier@gmail.com
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package server
  15. import (
  16. "encoding/json"
  17. "net/http"
  18. "github.com/fatedier/frp/pkg/config"
  19. "github.com/fatedier/frp/pkg/consts"
  20. "github.com/fatedier/frp/pkg/metrics/mem"
  21. "github.com/fatedier/frp/pkg/util/log"
  22. "github.com/fatedier/frp/pkg/util/version"
  23. "github.com/gorilla/mux"
  24. )
  25. type GeneralResponse struct {
  26. Code int
  27. Msg string
  28. }
  29. type serverInfoResp struct {
  30. Version string `json:"version"`
  31. BindPort int `json:"bind_port"`
  32. BindUDPPort int `json:"bind_udp_port"`
  33. VhostHTTPPort int `json:"vhost_http_port"`
  34. VhostHTTPSPort int `json:"vhost_https_port"`
  35. KCPBindPort int `json:"kcp_bind_port"`
  36. SubdomainHost string `json:"subdomain_host"`
  37. MaxPoolCount int64 `json:"max_pool_count"`
  38. MaxPortsPerClient int64 `json:"max_ports_per_client"`
  39. HeartBeatTimeout int64 `json:"heart_beat_timeout"`
  40. TotalTrafficIn int64 `json:"total_traffic_in"`
  41. TotalTrafficOut int64 `json:"total_traffic_out"`
  42. CurConns int64 `json:"cur_conns"`
  43. ClientCounts int64 `json:"client_counts"`
  44. ProxyTypeCounts map[string]int64 `json:"proxy_type_count"`
  45. }
  46. // /healthz
  47. func (svr *Service) Healthz(w http.ResponseWriter, r *http.Request) {
  48. w.WriteHeader(200)
  49. }
  50. // api/serverinfo
  51. func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
  52. res := GeneralResponse{Code: 200}
  53. defer func() {
  54. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  55. w.WriteHeader(res.Code)
  56. if len(res.Msg) > 0 {
  57. w.Write([]byte(res.Msg))
  58. }
  59. }()
  60. log.Info("Http request: [%s]", r.URL.Path)
  61. serverStats := mem.StatsCollector.GetServer()
  62. svrResp := serverInfoResp{
  63. Version: version.Full(),
  64. BindPort: svr.cfg.BindPort,
  65. BindUDPPort: svr.cfg.BindUDPPort,
  66. VhostHTTPPort: svr.cfg.VhostHTTPPort,
  67. VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
  68. KCPBindPort: svr.cfg.KCPBindPort,
  69. SubdomainHost: svr.cfg.SubDomainHost,
  70. MaxPoolCount: svr.cfg.MaxPoolCount,
  71. MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
  72. HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
  73. TotalTrafficIn: serverStats.TotalTrafficIn,
  74. TotalTrafficOut: serverStats.TotalTrafficOut,
  75. CurConns: serverStats.CurConns,
  76. ClientCounts: serverStats.ClientCounts,
  77. ProxyTypeCounts: serverStats.ProxyTypeCounts,
  78. }
  79. buf, _ := json.Marshal(&svrResp)
  80. res.Msg = string(buf)
  81. }
  82. type BaseOutConf struct {
  83. config.BaseProxyConf
  84. }
  85. type TCPOutConf struct {
  86. BaseOutConf
  87. RemotePort int `json:"remote_port"`
  88. }
  89. type TCPMuxOutConf struct {
  90. BaseOutConf
  91. config.DomainConf
  92. Multiplexer string `json:"multiplexer"`
  93. }
  94. type UDPOutConf struct {
  95. BaseOutConf
  96. RemotePort int `json:"remote_port"`
  97. }
  98. type HTTPOutConf struct {
  99. BaseOutConf
  100. config.DomainConf
  101. Locations []string `json:"locations"`
  102. HostHeaderRewrite string `json:"host_header_rewrite"`
  103. }
  104. type HTTPSOutConf struct {
  105. BaseOutConf
  106. config.DomainConf
  107. }
  108. type STCPOutConf struct {
  109. BaseOutConf
  110. }
  111. type XTCPOutConf struct {
  112. BaseOutConf
  113. }
  114. func getConfByType(proxyType string) interface{} {
  115. switch proxyType {
  116. case consts.TCPProxy:
  117. return &TCPOutConf{}
  118. case consts.TCPMuxProxy:
  119. return &TCPMuxOutConf{}
  120. case consts.UDPProxy:
  121. return &UDPOutConf{}
  122. case consts.HTTPProxy:
  123. return &HTTPOutConf{}
  124. case consts.HTTPSProxy:
  125. return &HTTPSOutConf{}
  126. case consts.STCPProxy:
  127. return &STCPOutConf{}
  128. case consts.XTCPProxy:
  129. return &XTCPOutConf{}
  130. default:
  131. return nil
  132. }
  133. }
  134. // Get proxy info.
  135. type ProxyStatsInfo struct {
  136. Name string `json:"name"`
  137. Conf interface{} `json:"conf"`
  138. TodayTrafficIn int64 `json:"today_traffic_in"`
  139. TodayTrafficOut int64 `json:"today_traffic_out"`
  140. CurConns int64 `json:"cur_conns"`
  141. LastStartTime string `json:"last_start_time"`
  142. LastCloseTime string `json:"last_close_time"`
  143. Status string `json:"status"`
  144. }
  145. type GetProxyInfoResp struct {
  146. Proxies []*ProxyStatsInfo `json:"proxies"`
  147. }
  148. // api/proxy/:type
  149. func (svr *Service) APIProxyByType(w http.ResponseWriter, r *http.Request) {
  150. res := GeneralResponse{Code: 200}
  151. params := mux.Vars(r)
  152. proxyType := params["type"]
  153. defer func() {
  154. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  155. w.WriteHeader(res.Code)
  156. if len(res.Msg) > 0 {
  157. w.Write([]byte(res.Msg))
  158. }
  159. }()
  160. log.Info("Http request: [%s]", r.URL.Path)
  161. proxyInfoResp := GetProxyInfoResp{}
  162. proxyInfoResp.Proxies = svr.getProxyStatsByType(proxyType)
  163. buf, _ := json.Marshal(&proxyInfoResp)
  164. res.Msg = string(buf)
  165. }
  166. func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxyStatsInfo) {
  167. proxyStats := mem.StatsCollector.GetProxiesByType(proxyType)
  168. proxyInfos = make([]*ProxyStatsInfo, 0, len(proxyStats))
  169. for _, ps := range proxyStats {
  170. proxyInfo := &ProxyStatsInfo{}
  171. if pxy, ok := svr.pxyManager.GetByName(ps.Name); ok {
  172. content, err := json.Marshal(pxy.GetConf())
  173. if err != nil {
  174. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  175. continue
  176. }
  177. proxyInfo.Conf = getConfByType(ps.Type)
  178. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  179. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  180. continue
  181. }
  182. proxyInfo.Status = consts.Online
  183. } else {
  184. proxyInfo.Status = consts.Offline
  185. }
  186. proxyInfo.Name = ps.Name
  187. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  188. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  189. proxyInfo.CurConns = ps.CurConns
  190. proxyInfo.LastStartTime = ps.LastStartTime
  191. proxyInfo.LastCloseTime = ps.LastCloseTime
  192. proxyInfos = append(proxyInfos, proxyInfo)
  193. }
  194. return
  195. }
  196. // Get proxy info by name.
  197. type GetProxyStatsResp struct {
  198. Name string `json:"name"`
  199. Conf interface{} `json:"conf"`
  200. TodayTrafficIn int64 `json:"today_traffic_in"`
  201. TodayTrafficOut int64 `json:"today_traffic_out"`
  202. CurConns int64 `json:"cur_conns"`
  203. LastStartTime string `json:"last_start_time"`
  204. LastCloseTime string `json:"last_close_time"`
  205. Status string `json:"status"`
  206. }
  207. // api/proxy/:type/:name
  208. func (svr *Service) APIProxyByTypeAndName(w http.ResponseWriter, r *http.Request) {
  209. res := GeneralResponse{Code: 200}
  210. params := mux.Vars(r)
  211. proxyType := params["type"]
  212. name := params["name"]
  213. defer func() {
  214. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  215. w.WriteHeader(res.Code)
  216. if len(res.Msg) > 0 {
  217. w.Write([]byte(res.Msg))
  218. }
  219. }()
  220. log.Info("Http request: [%s]", r.URL.Path)
  221. proxyStatsResp := GetProxyStatsResp{}
  222. proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
  223. if res.Code != 200 {
  224. return
  225. }
  226. buf, _ := json.Marshal(&proxyStatsResp)
  227. res.Msg = string(buf)
  228. }
  229. func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName string) (proxyInfo GetProxyStatsResp, code int, msg string) {
  230. proxyInfo.Name = proxyName
  231. ps := mem.StatsCollector.GetProxiesByTypeAndName(proxyType, proxyName)
  232. if ps == nil {
  233. code = 404
  234. msg = "no proxy info found"
  235. } else {
  236. if pxy, ok := svr.pxyManager.GetByName(proxyName); ok {
  237. content, err := json.Marshal(pxy.GetConf())
  238. if err != nil {
  239. log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err)
  240. code = 400
  241. msg = "parse conf error"
  242. return
  243. }
  244. proxyInfo.Conf = getConfByType(ps.Type)
  245. if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
  246. log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
  247. code = 400
  248. msg = "parse conf error"
  249. return
  250. }
  251. proxyInfo.Status = consts.Online
  252. } else {
  253. proxyInfo.Status = consts.Offline
  254. }
  255. proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
  256. proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
  257. proxyInfo.CurConns = ps.CurConns
  258. proxyInfo.LastStartTime = ps.LastStartTime
  259. proxyInfo.LastCloseTime = ps.LastCloseTime
  260. code = 200
  261. }
  262. return
  263. }
  264. // api/traffic/:name
  265. type GetProxyTrafficResp struct {
  266. Name string `json:"name"`
  267. TrafficIn []int64 `json:"traffic_in"`
  268. TrafficOut []int64 `json:"traffic_out"`
  269. }
  270. func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {
  271. res := GeneralResponse{Code: 200}
  272. params := mux.Vars(r)
  273. name := params["name"]
  274. defer func() {
  275. log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
  276. w.WriteHeader(res.Code)
  277. if len(res.Msg) > 0 {
  278. w.Write([]byte(res.Msg))
  279. }
  280. }()
  281. log.Info("Http request: [%s]", r.URL.Path)
  282. trafficResp := GetProxyTrafficResp{}
  283. trafficResp.Name = name
  284. proxyTrafficInfo := mem.StatsCollector.GetProxyTraffic(name)
  285. if proxyTrafficInfo == nil {
  286. res.Code = 404
  287. res.Msg = "no proxy info found"
  288. return
  289. }
  290. trafficResp.TrafficIn = proxyTrafficInfo.TrafficIn
  291. trafficResp.TrafficOut = proxyTrafficInfo.TrafficOut
  292. buf, _ := json.Marshal(&trafficResp)
  293. res.Msg = string(buf)
  294. }