package common import ( "bufio" "crypto/rand" "encoding/binary" "encoding/hex" "fmt" "io" "net" "git.cheetah.cat/cheetah/opentetraflex-go/common/tmkind" ) type TerminalClient struct { address string conn net.Conn netWriter *bufio.Writer netReader *bufio.Reader HandlerMap map[uint32]chan HandlerResponse RX chan *TerminalMessageResponse GroupConfig []GroupConfig RegistrationInfo RegistrationInfo } func NewTerminalClient(address string) (tc *TerminalClient) { return &TerminalClient{ address: address, RX: make(chan *TerminalMessageResponse), HandlerMap: make(map[uint32]chan HandlerResponse), } } 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 { panic(err) } 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) (err error) { // return nil } func (tc *TerminalClient) PTTRequest() { // IpApiCallPttRequest } /* 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) */ 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 } } }