mirror of https://github.com/q191201771/lal.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.7 KiB
Go
177 lines
4.7 KiB
Go
// Copyright 2020, Chef. All rights reserved.
|
|
// https://github.com/q191201771/lal
|
|
//
|
|
// Use of this source code is governed by a MIT-style license
|
|
// that can be found in the License file.
|
|
//
|
|
// Author: Chef (191201771@qq.com)
|
|
|
|
package httpts
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/q191201771/lal/pkg/mpegts"
|
|
|
|
"github.com/q191201771/lal/pkg/base"
|
|
"github.com/q191201771/naza/pkg/connection"
|
|
"github.com/q191201771/naza/pkg/nazahttp"
|
|
"github.com/q191201771/naza/pkg/nazalog"
|
|
)
|
|
|
|
var tsHTTPResponseHeader []byte
|
|
|
|
type SubSession struct {
|
|
uniqueKey string
|
|
IsFresh bool
|
|
|
|
scheme string
|
|
|
|
pathWithRawQuery string
|
|
headers map[string]string
|
|
urlCtx base.URLContext
|
|
|
|
conn connection.Connection
|
|
prevConnStat connection.Stat
|
|
staleStat *connection.Stat
|
|
stat base.StatSession
|
|
}
|
|
|
|
func NewSubSession(conn net.Conn, scheme string) *SubSession {
|
|
uk := base.GenUKTSSubSession()
|
|
s := &SubSession{
|
|
uniqueKey: uk,
|
|
scheme: scheme,
|
|
IsFresh: true,
|
|
conn: connection.New(conn, func(option *connection.Option) {
|
|
option.ReadBufSize = readBufSize
|
|
option.WriteChanSize = wChanSize
|
|
option.WriteTimeoutMS = subSessionWriteTimeoutMS
|
|
}),
|
|
stat: base.StatSession{
|
|
Protocol: base.ProtocolHTTPTS,
|
|
SessionID: uk,
|
|
StartTime: time.Now().Format("2006-01-02 15:04:05.999"),
|
|
RemoteAddr: conn.RemoteAddr().String(),
|
|
},
|
|
}
|
|
nazalog.Infof("[%s] lifecycle new httpts SubSession. session=%p, remote addr=%s", uk, s, conn.RemoteAddr().String())
|
|
return s
|
|
}
|
|
|
|
// TODO chef: read request timeout
|
|
func (session *SubSession) ReadRequest() (err error) {
|
|
defer func() {
|
|
if err != nil {
|
|
session.Dispose()
|
|
}
|
|
}()
|
|
|
|
var requestLine string
|
|
if requestLine, session.headers, err = nazahttp.ReadHTTPHeader(session.conn); err != nil {
|
|
return
|
|
}
|
|
if _, session.pathWithRawQuery, _, err = nazahttp.ParseHTTPRequestLine(requestLine); err != nil {
|
|
return
|
|
}
|
|
|
|
rawURL := fmt.Sprintf("%s://%s%s", session.scheme, session.headers["Host"], session.pathWithRawQuery)
|
|
_ = rawURL
|
|
|
|
session.urlCtx, err = base.ParseHTTPTSURL(rawURL, session.scheme == "https")
|
|
return
|
|
}
|
|
|
|
func (session *SubSession) RunLoop() error {
|
|
buf := make([]byte, 128)
|
|
_, err := session.conn.Read(buf)
|
|
return err
|
|
}
|
|
|
|
func (session *SubSession) WriteHTTPResponseHeader() {
|
|
nazalog.Debugf("[%s] > W http response header.", session.uniqueKey)
|
|
session.WriteRawPacket(tsHTTPResponseHeader)
|
|
}
|
|
|
|
func (session *SubSession) WriteFragmentHeader() {
|
|
nazalog.Debugf("[%s] > W http response header.", session.uniqueKey)
|
|
session.WriteRawPacket(mpegts.FixedFragmentHeader)
|
|
}
|
|
|
|
func (session *SubSession) WriteRawPacket(pkt []byte) {
|
|
_, _ = session.conn.Write(pkt)
|
|
}
|
|
|
|
func (session *SubSession) Dispose() error {
|
|
nazalog.Infof("[%s] lifecycle dispose httpts SubSession.", session.uniqueKey)
|
|
return session.conn.Close()
|
|
}
|
|
|
|
func (session *SubSession) UpdateStat(intervalSec uint32) {
|
|
currStat := session.conn.GetStat()
|
|
rDiff := currStat.ReadBytesSum - session.prevConnStat.ReadBytesSum
|
|
session.stat.ReadBitrate = int(rDiff * 8 / 1024 / uint64(intervalSec))
|
|
wDiff := currStat.WroteBytesSum - session.prevConnStat.WroteBytesSum
|
|
session.stat.WriteBitrate = int(wDiff * 8 / 1024 / uint64(intervalSec))
|
|
session.stat.Bitrate = session.stat.WriteBitrate
|
|
session.prevConnStat = currStat
|
|
}
|
|
|
|
func (session *SubSession) GetStat() base.StatSession {
|
|
connStat := session.conn.GetStat()
|
|
session.stat.ReadBytesSum = connStat.ReadBytesSum
|
|
session.stat.WroteBytesSum = connStat.WroteBytesSum
|
|
return session.stat
|
|
}
|
|
|
|
func (session *SubSession) IsAlive() (readAlive, writeAlive bool) {
|
|
currStat := session.conn.GetStat()
|
|
if session.staleStat == nil {
|
|
session.staleStat = new(connection.Stat)
|
|
*session.staleStat = currStat
|
|
return true, true
|
|
}
|
|
|
|
readAlive = !(currStat.ReadBytesSum-session.staleStat.ReadBytesSum == 0)
|
|
writeAlive = !(currStat.WroteBytesSum-session.staleStat.WroteBytesSum == 0)
|
|
*session.staleStat = currStat
|
|
return
|
|
}
|
|
|
|
func (session *SubSession) URL() string {
|
|
return session.urlCtx.URL
|
|
}
|
|
|
|
func (session *SubSession) AppName() string {
|
|
return session.urlCtx.PathWithoutLastItem
|
|
}
|
|
|
|
func (session *SubSession) StreamName() string {
|
|
return strings.TrimSuffix(session.urlCtx.LastItemOfPath, ".ts")
|
|
}
|
|
|
|
func (session *SubSession) RawQuery() string {
|
|
return session.urlCtx.RawQuery
|
|
}
|
|
|
|
func (session *SubSession) UniqueKey() string {
|
|
return session.uniqueKey
|
|
}
|
|
|
|
func init() {
|
|
tsHTTPResponseHeaderStr := "HTTP/1.1 200 OK\r\n" +
|
|
"Server: " + base.LALHTTPTSSubSessionServer + "\r\n" +
|
|
"Cache-Control: no-cache\r\n" +
|
|
"Content-Type: video/mp2t\r\n" +
|
|
"Connection: close\r\n" +
|
|
"Expires: -1\r\n" +
|
|
"Pragma: no-cache\r\n" +
|
|
"Access-Control-Allow-Origin: *\r\n" +
|
|
"\r\n"
|
|
|
|
tsHTTPResponseHeader = []byte(tsHTTPResponseHeaderStr)
|
|
}
|