mirror of
https://github.com/lkmio/gb-cms.git
synced 2025-12-24 11:51:52 +08:00
466 lines
21 KiB
Go
466 lines
21 KiB
Go
package api
|
||
|
||
import (
|
||
"gb-cms/common"
|
||
"gb-cms/dao"
|
||
"gb-cms/log"
|
||
"github.com/gorilla/mux"
|
||
"github.com/gorilla/websocket"
|
||
"net"
|
||
"net/http"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
type ApiServer struct {
|
||
router *mux.Router
|
||
upgrader *websocket.Upgrader
|
||
actionNames map[string]string
|
||
}
|
||
|
||
type InviteParams struct {
|
||
DeviceID string `json:"serial"`
|
||
ChannelID string `json:"code"`
|
||
StartTime string `json:"starttime"`
|
||
EndTime string `json:"endtime"`
|
||
Setup string `json:"setup"`
|
||
Speed string `json:"speed"`
|
||
Token string `json:"token"`
|
||
Download bool `json:"download"`
|
||
streamId common.StreamID
|
||
}
|
||
|
||
type StreamParams struct {
|
||
Stream common.StreamID `json:"stream"` // Source
|
||
Session string `json:"session"` // 本次推拉流的会话ID
|
||
Protocol int `json:"protocol"` // 推拉流协议
|
||
RemoteAddr string `json:"remote_addr"` // peer地址
|
||
}
|
||
|
||
type PlayDoneParams struct {
|
||
StreamParams
|
||
Sink string `json:"sink"`
|
||
}
|
||
|
||
type QueryRecordParams struct {
|
||
DeviceID string `json:"serial"`
|
||
ChannelID string `json:"code"`
|
||
Timeout int `json:"timeout"`
|
||
StartTime string `json:"starttime"`
|
||
EndTime string `json:"endtime"`
|
||
//Type_ string `json:"type"`
|
||
Command string `json:"command"` // 云台控制命令 left/up/right/down/zoomin/zoomout
|
||
}
|
||
|
||
type DeviceChannelID struct {
|
||
DeviceID string `json:"device_id"`
|
||
ChannelID string `json:"channel_id"`
|
||
}
|
||
|
||
type SeekParams struct {
|
||
StreamId common.StreamID `json:"stream_id"`
|
||
Seconds int `json:"seconds"`
|
||
}
|
||
|
||
type BroadcastParams struct {
|
||
DeviceID string `json:"device_id"`
|
||
ChannelID string `json:"channel_id"`
|
||
StreamId common.StreamID `json:"stream_id"`
|
||
Setup *common.SetupType `json:"setup"`
|
||
}
|
||
|
||
type RecordParams struct {
|
||
StreamParams
|
||
Path string `json:"path"`
|
||
}
|
||
|
||
type SnapshotParams struct {
|
||
StreamParams
|
||
Codec string `json:"codec"`
|
||
KeyFrameData []byte `json:"key_frame_data"`
|
||
}
|
||
|
||
type StreamIDParams struct {
|
||
StreamID common.StreamID `json:"streamid"`
|
||
Command string `json:"command"`
|
||
Scale float64 `json:"scale"`
|
||
}
|
||
|
||
type PageQuery struct {
|
||
PageNumber *int `json:"page_number"` // 页数
|
||
PageSize *int `json:"page_size"` // 每页大小
|
||
TotalPages int `json:"total_pages"` // 总页数
|
||
TotalCount int `json:"total_count"` // 总记录数
|
||
Data interface{} `json:"data"`
|
||
}
|
||
|
||
type SetMediaTransportReq struct {
|
||
DeviceID string `json:"serial"`
|
||
MediaTransport string `json:"media_transport"`
|
||
MediaTransportMode string `json:"media_transport_mode"`
|
||
}
|
||
|
||
// QueryDeviceChannel 查询设备和通道的参数
|
||
type QueryDeviceChannel struct {
|
||
DeviceID string `json:"serial"`
|
||
GroupID string `json:"dir_serial"`
|
||
PCode string `json:"pcode"`
|
||
Start int `json:"start"`
|
||
Limit int `json:"limit"`
|
||
Keyword string `json:"q"`
|
||
Online string `json:"online"`
|
||
Enable string `json:"enable"`
|
||
ChannelType string `json:"channel_type"` // dir-查询子目录
|
||
Order string `json:"order"` // asc/desc
|
||
Sort string `json:"sort"` // Channel-根据数据库ID排序/iD-根据通道ID排序
|
||
SMS string `json:"sms"`
|
||
Filter string `json:"filter"`
|
||
|
||
Priority int `json:"priority"` // 报警参数
|
||
Method string `json:"method"`
|
||
StartTime string `json:"starttime"`
|
||
EndTime string `json:"endtime"`
|
||
}
|
||
|
||
type DeleteDevice struct {
|
||
DeviceID string `json:"serial"`
|
||
IP string `json:"ip"`
|
||
Forbid bool `json:"forbid"`
|
||
UA string `json:"ua"`
|
||
}
|
||
|
||
type SetEnable struct {
|
||
ID int `json:"id"`
|
||
Enable bool `json:"enable"`
|
||
ShareAllChannel bool `json:"shareallchannel"`
|
||
}
|
||
|
||
type QueryCascadeChannelList struct {
|
||
QueryDeviceChannel
|
||
ID string `json:"id"`
|
||
Related bool `json:"related"` // 只看已选择
|
||
Reverse bool `json:"reverse"`
|
||
}
|
||
|
||
type ChannelListResult struct {
|
||
ChannelCount int `json:"ChannelCount"`
|
||
ChannelList []*LiveGBSChannel `json:"ChannelList"`
|
||
}
|
||
|
||
type CascadeChannel struct {
|
||
CascadeID string
|
||
*LiveGBSChannel
|
||
}
|
||
|
||
type CustomChannel struct {
|
||
DeviceID string `json:"serial"`
|
||
ChannelID string `json:"code"`
|
||
CustomID string `json:"id"`
|
||
}
|
||
|
||
type DeviceInfo struct {
|
||
DeviceID string `json:"serial"`
|
||
CustomName string `json:"custom_name"`
|
||
MediaTransport string `json:"media_transport"`
|
||
MediaTransportMode string `json:"media_transport_mode"`
|
||
StreamMode string `json:"stream_mode"`
|
||
SMSID string `json:"sms_id"`
|
||
SMSGroupID string `json:"sms_group_id"`
|
||
RecvStreamIP string `json:"recv_stream_ip"`
|
||
ContactIP string `json:"contact_ip"`
|
||
Charset string `json:"charset"`
|
||
CatalogInterval int `json:"catalog_interval"`
|
||
SubscribeInterval int `json:"subscribe_interval"`
|
||
CatalogSubscribe bool `json:"catalog_subscribe"`
|
||
AlarmSubscribe bool `json:"alarm_subscribe"`
|
||
PositionSubscribe bool `json:"position_subscribe"`
|
||
PTZSubscribe bool `json:"ptz_subscribe"`
|
||
RecordCenter bool `json:"record_center"`
|
||
RecordIndistinct bool `json:"record_indistinct"`
|
||
CivilCodeFirst bool `json:"civil_code_first"`
|
||
KeepOriginalTree bool `json:"keep_original_tree"`
|
||
Password string `json:"password"`
|
||
DropChannelType string `json:"drop_channel_type"`
|
||
Longitude float64 `json:"longitude"`
|
||
Latitude float64 `json:"latitude"`
|
||
}
|
||
|
||
type responseRecorder struct {
|
||
http.ResponseWriter
|
||
statusCode int
|
||
body []byte
|
||
}
|
||
|
||
func (r *responseRecorder) WriteHeader(statusCode int) {
|
||
r.statusCode = statusCode
|
||
r.ResponseWriter.WriteHeader(statusCode)
|
||
}
|
||
|
||
func (r *responseRecorder) Write(b []byte) (int, error) {
|
||
r.body = append(r.body, b...)
|
||
return r.ResponseWriter.Write(b)
|
||
}
|
||
|
||
type Empty struct {
|
||
}
|
||
|
||
var apiServer *ApiServer
|
||
|
||
func init() {
|
||
apiServer = &ApiServer{
|
||
upgrader: &websocket.Upgrader{
|
||
CheckOrigin: func(r *http.Request) bool {
|
||
return true
|
||
},
|
||
},
|
||
|
||
actionNames: make(map[string]string, 32),
|
||
router: mux.NewRouter(),
|
||
}
|
||
}
|
||
|
||
// 验证和刷新token
|
||
func withVerify(f func(w http.ResponseWriter, req *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||
return func(w http.ResponseWriter, req *http.Request) {
|
||
cookie, err := req.Cookie("token")
|
||
if err != nil {
|
||
w.WriteHeader(http.StatusUnauthorized)
|
||
return
|
||
}
|
||
|
||
ok := TokenManager.Refresh(cookie.Value, time.Now())
|
||
if !ok {
|
||
w.WriteHeader(http.StatusUnauthorized)
|
||
return
|
||
} else if AdminMD5 == PwdMD5 && req.URL.Path != "/api/v1/modifypassword" && req.URL.Path != "/api/v1/userinfo" {
|
||
// 如果没有修改默认密码, 只允许放行这2个接口
|
||
return
|
||
}
|
||
|
||
f(w, req)
|
||
}
|
||
}
|
||
|
||
func withVerify2(onSuccess func(w http.ResponseWriter, req *http.Request), onFailure func(w http.ResponseWriter, req *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||
return func(w http.ResponseWriter, req *http.Request) {
|
||
cookie, err := req.Cookie("token")
|
||
if err == nil && TokenManager.Refresh(cookie.Value, time.Now()) {
|
||
onSuccess(w, req)
|
||
} else {
|
||
onFailure(w, req)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 注册带统计的api
|
||
func (api *ApiServer) registerStatisticsHandler(actionName, path string, handler func(http.ResponseWriter, *http.Request)) {
|
||
api.router.HandleFunc(path, handler)
|
||
api.actionNames[path] = actionName
|
||
}
|
||
|
||
type SnapshotFilter struct {
|
||
}
|
||
|
||
func (f *SnapshotFilter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||
if "" != r.URL.Query().Get("preview_snapshot") {
|
||
t := r.URL.Query().Get("t")
|
||
ok := DefaultSnapshotManager.Get(t, 2*time.Second)
|
||
if !ok {
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
}
|
||
|
||
http.FileServer(http.Dir("./snapshot")).ServeHTTP(w, r)
|
||
}
|
||
|
||
func StartApiServer(addr string) {
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_play", common.WithJsonParams(apiServer.OnPlay, &PlayDoneParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_play_done", common.WithJsonParams(apiServer.OnPlayDone, &PlayDoneParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_publish", common.WithJsonParams(apiServer.OnPublish, &StreamParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_publish_done", common.WithJsonParams(apiServer.OnPublishDone, &StreamParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_idle_timeout", common.WithJsonParams(apiServer.OnIdleTimeout, &StreamParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_receive_timeout", common.WithJsonParams(apiServer.OnReceiveTimeout, &StreamParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_record", common.WithJsonParams(apiServer.OnRecord, &RecordParams{}))
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_started", apiServer.OnStarted)
|
||
apiServer.router.HandleFunc("/api/v1/hook/on_snapshot", apiServer.OnSnapshot)
|
||
|
||
apiServer.registerStatisticsHandler("开始预览", "/api/v1/stream/start", withVerify(common.WithFormDataParams(apiServer.OnStreamStart, InviteParams{}))) // 实时预览
|
||
apiServer.registerStatisticsHandler("停止预览", "/api/v1/stream/stop", withVerify(common.WithFormDataParams(apiServer.OnCloseLiveStream, InviteParams{}))) // 关闭实时预览
|
||
apiServer.registerStatisticsHandler("开始回放/下载", "/api/v1/playback/start", withVerify(common.WithFormDataParams(apiServer.OnPlaybackStart, InviteParams{}))) // 回放/下载
|
||
apiServer.registerStatisticsHandler("停止回放/下载", "/api/v1/playback/stop", withVerify(common.WithFormDataParams(apiServer.OnCloseStream, StreamIDParams{}))) // 关闭回放/下载
|
||
apiServer.registerStatisticsHandler("回放控制", "/api/v1/playback/control", withVerify(common.WithFormDataParams(apiServer.OnPlaybackControl, StreamIDParams{}))) // 回放控制
|
||
|
||
apiServer.router.HandleFunc("/api/v1/device/list", withVerify(common.WithQueryStringParams(apiServer.OnDeviceList, QueryDeviceChannel{}))) // 查询设备列表
|
||
apiServer.router.HandleFunc("/api/v1/device/channeltree", withVerify(common.WithQueryStringParams(apiServer.OnDeviceTree, QueryDeviceChannel{}))) // 设备树
|
||
apiServer.router.HandleFunc("/api/v1/device/channellist", withVerify(common.WithQueryStringParams(apiServer.OnChannelList, QueryDeviceChannel{}))) // 查询通道列表
|
||
apiServer.registerStatisticsHandler("手动刷新通道", "/api/v1/device/fetchcatalog", withVerify(common.WithQueryStringParams(apiServer.OnCatalogQuery, QueryDeviceChannel{}))) // 更新通道
|
||
apiServer.registerStatisticsHandler("删除设备", "/api/v1/device/remove", withVerify(common.WithFormDataParams(apiServer.OnDeviceRemove, DeleteDevice{}))) // 删除设备
|
||
apiServer.registerStatisticsHandler("设置设备媒体传输模式", "/api/v1/device/setmediatransport", withVerify(common.WithFormDataParams(apiServer.OnDeviceMediaTransportSet, SetMediaTransportReq{}))) // 设置设备媒体传输模式
|
||
|
||
apiServer.registerStatisticsHandler("查询录像列表", "/api/v1/playback/recordlist", withVerify(common.WithQueryStringParams(apiServer.OnRecordList, QueryRecordParams{}))) // 查询录像列表
|
||
apiServer.router.HandleFunc("/api/v1/stream/info", withVerify(apiServer.OnStreamInfo))
|
||
apiServer.router.HandleFunc("/api/v1/playback/streaminfo", withVerify(apiServer.OnStreamInfo))
|
||
apiServer.router.HandleFunc("/api/v1/device/session/list", withVerify(common.WithQueryStringParams(apiServer.OnSessionList, QueryDeviceChannel{}))) // 推流列表
|
||
apiServer.router.HandleFunc("/api/v1/device/session/stop", withVerify(common.WithFormDataParams(apiServer.OnSessionStop, StreamIDParams{}))) // 关闭流
|
||
apiServer.router.HandleFunc("/api/v1/device/setchannelid", withVerify(common.WithFormDataParams(apiServer.OnCustomChannelSet, CustomChannel{}))) // 自定义通道ID
|
||
|
||
apiServer.router.HandleFunc("/api/v1/playback/seek", common.WithJsonResponse(apiServer.OnSeekPlayback, &SeekParams{})) // 回放seek
|
||
apiServer.registerStatisticsHandler("云台控制", "/api/v1/control/ptz", withVerify(common.WithFormDataParams(apiServer.OnPTZControl, QueryRecordParams{}))) // 云台控制
|
||
|
||
apiServer.router.HandleFunc("/api/v1/cascade/list", withVerify(common.WithQueryStringParams(apiServer.OnPlatformList, QueryDeviceChannel{}))) // 级联设备列表
|
||
apiServer.registerStatisticsHandler("添加级联设备", "/api/v1/cascade/save", withVerify(common.WithFormDataParams(apiServer.OnPlatformAdd, LiveGBSCascade{}))) // 添加级联设备
|
||
apiServer.registerStatisticsHandler("设置级联设备状态", "/api/v1/cascade/setenable", withVerify(common.WithFormDataParams(apiServer.OnEnableSet, SetEnable{}))) // 使能级联设备
|
||
apiServer.registerStatisticsHandler("删除级联设备", "/api/v1/cascade/remove", withVerify(common.WithFormDataParams(apiServer.OnPlatformRemove, SetEnable{}))) // 删除级联设备
|
||
apiServer.router.HandleFunc("/api/v1/cascade/channellist", withVerify(common.WithQueryStringParams(apiServer.OnPlatformChannelList, QueryCascadeChannelList{}))) // 级联设备通道列表
|
||
|
||
apiServer.router.HandleFunc("/api/v1/cascade/savechannels", withVerify(apiServer.OnPlatformChannelBind)) // 级联绑定通道
|
||
apiServer.router.HandleFunc("/api/v1/cascade/removechannels", withVerify(apiServer.OnPlatformChannelUnbind)) // 级联解绑通道
|
||
apiServer.router.HandleFunc("/api/v1/cascade/setshareallchannel", withVerify(common.WithFormDataParams(apiServer.OnShareAllChannel, SetEnable{}))) // 开启或取消级联所有通道
|
||
apiServer.registerStatisticsHandler("推送目录", "/api/v1/cascade/pushcatalog", withVerify(common.WithFormDataParams(apiServer.OnCatalogPush, SetEnable{}))) // 推送目录
|
||
apiServer.registerStatisticsHandler("编辑设备信息", "/api/v1/device/setinfo", withVerify(common.WithFormDataParams(apiServer.OnDeviceInfoSet, DeviceInfo{}))) // 编辑设备信息
|
||
apiServer.router.HandleFunc("/api/v1/alarm/list", withVerify(common.WithQueryStringParams(apiServer.OnAlarmList, QueryDeviceChannel{}))) // 报警查询
|
||
apiServer.registerStatisticsHandler("删除报警", "/api/v1/alarm/remove", withVerify(common.WithFormDataParams(apiServer.OnAlarmRemove, SetEnable{}))) // 删除报警
|
||
apiServer.registerStatisticsHandler("清空报警", "/api/v1/alarm/clear", withVerify(common.WithFormDataParams(apiServer.OnAlarmClear, Empty{}))) // 清空报警
|
||
apiServer.router.HandleFunc("/api/v1/log/list", withVerify(common.WithQueryStringParams(apiServer.OnLogList, QueryDeviceChannel{}))) // 操作日志
|
||
apiServer.router.HandleFunc("/api/v1/log/clear", withVerify(common.WithQueryStringParams(apiServer.OnLogClear, Empty{}))) // 操作日志
|
||
|
||
apiServer.router.HandleFunc("/api/v1/device/statuslog", withVerify(common.WithQueryStringParams(apiServer.OnStatusLogList, QueryDeviceChannel{}))) // 设备上下线统计
|
||
|
||
// 暂未开发
|
||
apiServer.router.HandleFunc("/api/v1/sms/list", withVerify(func(w http.ResponseWriter, req *http.Request) {})) // 流媒体服务器列表
|
||
apiServer.router.HandleFunc("/api/v1/cloudrecord/querychannels", withVerify(func(w http.ResponseWriter, req *http.Request) {})) // 云端录像
|
||
apiServer.router.HandleFunc("/api/v1/user/list", withVerify(func(w http.ResponseWriter, req *http.Request) {})) // 用户管理
|
||
apiServer.router.HandleFunc("/api/v1/getbaseconfig", withVerify(common.WithFormDataParams(apiServer.OnGetBaseConfig, Empty{})))
|
||
apiServer.router.HandleFunc("/api/v1/setbaseconfig", withVerify(common.WithFormDataParams(apiServer.OnSetBaseConfig, Empty{})))
|
||
apiServer.router.HandleFunc("/api/v1/gm/cert/list", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
apiServer.router.HandleFunc("/api/v1/getrequestkey", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
apiServer.router.HandleFunc("/api/v1/getrequestkey", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
apiServer.router.HandleFunc("/api/v1/device/positionlog", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
apiServer.router.HandleFunc("/api/v1/device/streamlog", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
apiServer.router.HandleFunc("/api/v1/record/list", withVerify(func(w http.ResponseWriter, req *http.Request) {}))
|
||
|
||
apiServer.registerStatisticsHandler("开始录制", "/api/v1/record/start", withVerify(apiServer.OnRecordStart)) // 开启录制
|
||
apiServer.registerStatisticsHandler("结束录制", "/api/v1/record/stop", withVerify(apiServer.OnRecordStop)) // 关闭录制
|
||
|
||
apiServer.router.HandleFunc("/api/v1/broadcast/invite", common.WithJsonResponse(apiServer.OnBroadcast, &BroadcastParams{Setup: &common.DefaultSetupType})) // 发起语音广播
|
||
apiServer.router.HandleFunc("/api/v1/broadcast/hangup", common.WithJsonResponse(apiServer.OnHangup, &BroadcastParams{})) // 挂断广播会话
|
||
apiServer.registerStatisticsHandler("发起对讲", "/api/v1/control/ws-talk/{device}/{channel}", withVerify(apiServer.OnTalk)) // 一对一语音对讲
|
||
|
||
apiServer.router.HandleFunc("/api/v1/jt/device/add", common.WithJsonResponse(apiServer.OnVirtualDeviceAdd, &dao.JTDeviceModel{}))
|
||
apiServer.router.HandleFunc("/api/v1/jt/device/edit", common.WithJsonResponse(apiServer.OnVirtualDeviceEdit, &dao.JTDeviceModel{}))
|
||
apiServer.router.HandleFunc("/api/v1/jt/device/remove", common.WithJsonResponse(apiServer.OnVirtualDeviceRemove, &dao.JTDeviceModel{}))
|
||
apiServer.router.HandleFunc("/api/v1/jt/device/list", common.WithJsonResponse(apiServer.OnVirtualDeviceList, &PageQuery{}))
|
||
|
||
apiServer.router.HandleFunc("/api/v1/jt/channel/add", common.WithJsonResponse(apiServer.OnVirtualChannelAdd, &dao.ChannelModel{}))
|
||
apiServer.router.HandleFunc("/api/v1/jt/channel/edit", common.WithJsonResponse(apiServer.OnVirtualChannelEdit, &dao.ChannelModel{}))
|
||
apiServer.router.HandleFunc("/api/v1/jt/channel/remove", common.WithJsonResponse(apiServer.OnVirtualChannelRemove, &dao.ChannelModel{}))
|
||
apiServer.registerStatisticsHandler("退出登录", "/api/v1/logout", func(writer http.ResponseWriter, req *http.Request) {
|
||
cookie, err := req.Cookie("token")
|
||
if err == nil {
|
||
TokenManager.Remove(cookie.Value)
|
||
writer.Header().Set("Location", "/login.html")
|
||
writer.WriteHeader(http.StatusFound)
|
||
return
|
||
}
|
||
})
|
||
|
||
registerLiveGBSApi()
|
||
|
||
apiServer.router.Use(func(handler http.Handler) http.Handler {
|
||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
now := time.Now()
|
||
name, ok := apiServer.actionNames[r.URL.Path]
|
||
recorder := &responseRecorder{ResponseWriter: w}
|
||
handler.ServeHTTP(recorder, r)
|
||
if !ok {
|
||
return
|
||
}
|
||
|
||
end := time.Now()
|
||
var address string
|
||
if common.Config.IP2RegionEnable {
|
||
host, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||
region, err := common.IP2Region(host)
|
||
if err == nil {
|
||
address = region
|
||
} else {
|
||
log.Sugar.Errorf("IP2Region error: %v", err)
|
||
}
|
||
}
|
||
|
||
// /api/v1/login
|
||
var username = "admin"
|
||
if r.URL.Path == "/api/v1/login" {
|
||
username = r.FormValue("username")
|
||
}
|
||
|
||
var status = "OK"
|
||
if recorder.statusCode == 0 {
|
||
recorder.statusCode = http.StatusOK
|
||
}
|
||
|
||
if recorder.statusCode != http.StatusOK {
|
||
status = string(recorder.body)
|
||
}
|
||
|
||
model := dao.LogModel{
|
||
Name: name,
|
||
Scheme: "HTTP",
|
||
Method: r.Method,
|
||
RequestURI: r.URL.Path,
|
||
RemoteAddr: r.RemoteAddr,
|
||
RemoteRegion: address,
|
||
Status: status,
|
||
StatusCode: recorder.statusCode,
|
||
StartAt: now.Format("2006-01-02 15:04:05"),
|
||
Duration: int(end.Sub(now).Seconds()),
|
||
Username: username,
|
||
}
|
||
|
||
err := dao.Log.Save(&model)
|
||
if err != nil {
|
||
log.Sugar.Errorf("Save log error: %v", err)
|
||
}
|
||
})
|
||
})
|
||
|
||
// 映射snapshot目录
|
||
filter := SnapshotFilter{}
|
||
apiServer.router.PathPrefix("/snapshot/").Handler(http.StripPrefix("/snapshot/", &filter))
|
||
|
||
// 前端路由
|
||
htmlRoot := "./html/"
|
||
fileServer := http.FileServer(http.Dir(htmlRoot))
|
||
apiServer.router.PathPrefix("/").HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||
// 处理无扩展名的路径,自动添加.html扩展名
|
||
path := request.URL.Path
|
||
if !strings.Contains(path, ".") {
|
||
// 检查是否存在对应的.html文件
|
||
htmlPath := htmlRoot + path + ".html"
|
||
if _, err := os.Stat(htmlPath); err == nil {
|
||
// 如果存在对应的.html文件,则直接返回该文件
|
||
http.ServeFile(writer, request, htmlPath)
|
||
return
|
||
}
|
||
}
|
||
|
||
fileServer.ServeHTTP(writer, request)
|
||
})
|
||
|
||
srv := &http.Server{
|
||
Handler: apiServer.router,
|
||
Addr: addr,
|
||
// Good practice: enforce timeouts for servers you create!
|
||
WriteTimeout: 30 * time.Second,
|
||
ReadTimeout: 30 * time.Second,
|
||
}
|
||
|
||
err := srv.ListenAndServe()
|
||
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
}
|