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.

368 lines
9.7 KiB
Go

1 year ago
package common
import (
"bufio"
"crypto/rand"
1 year ago
"encoding/binary"
"encoding/hex"
1 year ago
"fmt"
"io"
"net"
"strings"
"git.cheetah.cat/cheetah/opentetraflex-go/common/tmkind"
1 year ago
)
type TerminalClient struct {
address string
conn net.Conn
netWriter *bufio.Writer
netReader *bufio.Reader
1 year ago
HandlerMap map[uint32]chan HandlerResponse
1 year ago
RX chan *TerminalMessageResponse
GroupConfig []GroupConfig
RegistrationInfo RegistrationInfo
udpRTP_TX *net.UDPConn
1 year ago
}
func NewTerminalClient(address string) (tc *TerminalClient) {
return &TerminalClient{
address: address,
RX: make(chan *TerminalMessageResponse),
HandlerMap: make(map[uint32]chan HandlerResponse),
1 year ago
}
}
func (tc *TerminalClient) Connect() (err error) {
tc.conn, err = net.Dial("tcp", tc.address)
if err != nil {
return err
}
tc.netWriter = bufio.NewWriter(tc.conn)
tc.netReader = bufio.NewReader(tc.conn)
go tc.rxLoop()
return nil
}
func (tc *TerminalClient) Send(message *TerminalMessage) (err error) {
_, err = tc.netWriter.Write(message.Encode())
if err != nil {
return err
}
err = tc.netWriter.Flush()
if err != nil {
return err
}
return nil
}
func (tc *TerminalClient) Authenticate(addr TetraFlexAddress) (err error) {
randomBytes := make([]byte, 10)
_, err = rand.Read(randomBytes)
if err != nil {
return err
}
// 20160111
tfAuthReq, err := NewTMAuthReq(addr, 0, randomBytes, 1, "OpenTetraFlex-Go", 20230831, "1.0.0")
if err != nil {
return err
}
tc.HandlerMap[tfAuthReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfAuthReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfAuthReq.handler]
if !response.Success {
return response.Error
}
tc.RegistrationInfo, err = response.TMR.AsRegistrationInfo()
if err != nil {
return err
}
return nil
}
func (tc *TerminalClient) SubscribeEvents(messageTypes []tmkind.TetraFlexTerminalMessageKinds) (err error) {
tfNotReq, err := NewTMNotificationRequest(messageTypes)
if err != nil {
return err
}
tc.HandlerMap[tfNotReq.handler] = make(chan HandlerResponse)
err = tc.Send(tfNotReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfNotReq.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) AttachGroups(groups []GroupConfig) (err error) {
tfGroupAttachReq, err := NewTMIpApiGroupAttachRequest(groups)
if err != nil {
return nil
}
fmt.Println(hex.EncodeToString(tfGroupAttachReq.Encode()))
tc.HandlerMap[tfGroupAttachReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfGroupAttachReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfGroupAttachReq.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) CallSetup(address TetraFlexAddress, callType TetraFlexCallTypes, callPriority TetraFlexCallPriorities, hookCall bool, identityInfo TetraFlexIdentityInfo) (callRef byte, err error) {
tfCallSetupReq, err := NewTMIpApiCallSetupRequest(address, callType, callPriority, hookCall, identityInfo)
if err != nil {
return callRef, err
}
fmt.Println(hex.EncodeToString(tfCallSetupReq.Encode()))
tc.HandlerMap[tfCallSetupReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfCallSetupReq)
if err != nil {
return callRef, err
}
response := <-tc.HandlerMap[tfCallSetupReq.handler]
if !response.Success {
return callRef, response.Error
}
//fmt.Println(hex.EncodeToString(response.TMR.payload))
callRef, err = response.TMR.readByte()
if err != nil {
return callRef, err
}
return callRef, nil
}
func (tc *TerminalClient) CallDisconnect(callRef byte, disconnectCause TetraFlexCallDisconnectCauses) (err error) {
tfCallDisconnectReq, err := NewTMIpApiCallDisconnectRequest(callRef, disconnectCause)
if err != nil {
return nil
}
fmt.Println(hex.EncodeToString(tfCallDisconnectReq.Encode()))
tc.HandlerMap[tfCallDisconnectReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfCallDisconnectReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfCallDisconnectReq.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) CallConnect(callRef byte) (err error) {
tfCallConnectReq, err := NewTMIpApiCallConnectRequest(callRef)
if err != nil {
return nil
}
fmt.Println(hex.EncodeToString(tfCallConnectReq.Encode()))
tc.HandlerMap[tfCallConnectReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfCallConnectReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfCallConnectReq.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) CallStreamRequest(uint1 uint, callRef byte, streamRef byte, audioChannelType TetraFlexAudioChannelTypes) (err error) {
tfStreamReq, err := NewTMIpApiCallStreamRequest(uint1, callRef, streamRef, audioChannelType)
if err != nil {
return nil
}
fmt.Println(hex.EncodeToString(tfStreamReq.Encode()))
tc.HandlerMap[tfStreamReq.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfStreamReq)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfStreamReq.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) PTTRequest(callRef byte, identityInfo TetraFlexIdentityInfo, octaStateByte byte) (err error) {
// IpApiCallPttRequest
tfPTTRequest, err := NewTMIpApiCallPTTRequest(callRef, identityInfo, octaStateByte)
if err != nil {
return err
}
fmt.Println(hex.EncodeToString(tfPTTRequest.Encode()))
tc.HandlerMap[tfPTTRequest.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfPTTRequest)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfPTTRequest.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) PTTRelease(callRef byte) (err error) {
// IpApiCallPttRequest
tfPTTRelease, err := NewTMIpApiCallPTTRelease(callRef)
if err != nil {
return err
}
fmt.Println(hex.EncodeToString(tfPTTRelease.Encode()))
tc.HandlerMap[tfPTTRelease.handler] = make(chan HandlerResponse)
//fmt.Println(hex.EncodeToString(tfAuthReq.Encode()))
err = tc.Send(tfPTTRelease)
if err != nil {
return err
}
response := <-tc.HandlerMap[tfPTTRelease.handler]
if !response.Success {
return response.Error
}
return nil
}
func (tc *TerminalClient) RTPConnect() (err error) {
portNum := tc.RegistrationInfo.RTPPorts[0]
localAddress, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("0.0.0.0:%d", portNum))
parts := strings.Split(tc.address, ":")
remoteTXAddr := fmt.Sprintf("%s:%d", parts[0], portNum)
remoteAddress, _ := net.ResolveUDPAddr("udp", remoteTXAddr)
tc.udpRTP_TX, err = net.DialUDP("udp", localAddress, remoteAddress)
if err != nil {
return err
}
return nil
}
func (tc *TerminalClient) RTPSend(data []byte) (err error) {
//parts := strings.Split(tc.address, ":")
//remoteTXAddr := fmt.Sprintf("%s:%d", parts[0], tc.RegistrationInfo.RTPPorts[0])
//remoteAddress, _ := net.ResolveUDPAddr("udp", remoteTXAddr)
_, err = tc.udpRTP_TX.Write(data) //WriteToUDP(data, remoteAddress)
if err != nil {
return err
}
return nil
}
func (tc *TerminalClient) RTPConnected() bool {
if tc.udpRTP_TX != nil {
return true
}
return false
}
/*
groupAddr := common.NewAddressFromSSINumber(103)
identityNum := common.NewAddressFromSSINumber(1007)
response, err = common.NewTMIpApiCallSetupRequest(*groupAddr, common.CallTypeGroup, common.CallPriorityDefault, false, common.TetraFlexIdentityInfo{
Description: "blurb",
Kind: common.IdentityKindTerminal,
Address: *identityNum,
UnifiedSSIKinds: common.UnifiedKindPersonalNumber,
})
if err != nil {
panic(err)
}
fmt.Println(hex.EncodeToString(response.Encode()))
terminalClient.Send(response)
*/
1 year ago
func (tc *TerminalClient) rxLoop() {
var err error
for {
dataHeader := make([]byte, 2) //2 bytes for uint16
_, err = io.ReadFull(tc.netReader, dataHeader)
if err != nil {
panic(err)
}
payloadLength := binary.LittleEndian.Uint16(dataHeader)
fmt.Printf("length: %d bytes\n", payloadLength)
kindData := make([]byte, 2) //2 bytes for uint16
_, err = io.ReadFull(tc.netReader, kindData)
if err != nil {
panic(err)
}
messageKind := binary.LittleEndian.Uint16(kindData)
fmt.Printf("kind: %d\n", messageKind)
handlerData := make([]byte, 4) //4 bytes for uint32
_, err = io.ReadFull(tc.netReader, handlerData)
if err != nil {
panic(err)
}
messageHandler := binary.LittleEndian.Uint32(handlerData)
fmt.Printf("handler: %d\n", messageHandler)
dataPayload := make([]byte, payloadLength-(2+2+4)) //8 bytes for header
_, err = io.ReadFull(tc.netReader, dataPayload)
if err != nil {
panic(err)
}
parsedResp, err := NewTerminalMessageResponse(payloadLength, tmkind.TetraFlexTerminalMessageKinds(messageKind), messageHandler, dataPayload)
if err != nil {
panic(err)
}
if _, ok := tc.HandlerMap[messageHandler]; ok {
tc.HandlerMap[messageHandler] <- HandlerResponse{
Success: true,
TMR: parsedResp,
}
delete(tc.HandlerMap, messageHandler)
} else {
// Lets Handle KeepAlive for ourself
if parsedResp.Kind == tmkind.IpApiKeepAliveChallenge {
challenge, err := parsedResp.AsKeepAliveChallenge()
if err != nil {
panic(err)
}
response, err := NewTMKeepAliveResponse(challenge)
if err != nil {
panic(err)
}
err = tc.Send(response)
if err != nil {
panic(err)
}
continue
}
tc.RX <- parsedResp
}
1 year ago
}
}