def __init__(self, ac, app_id, app_name, serviceType=PHP):

        super().__init__(app_id, app_name)
        self.ac = ac
        self.tcpHost = (ac.CollectorAgentIp, ac.CollectorAgentPort)
        self.statHost = (ac.CollectorStatIp, ac.CollectorStatPort)
        self.spanHost = (ac.CollectorSpanIp, ac.CollectorSpanPort)
        TCLogger.debug("CollectorTcp %s CollectorStat %s CollectorSpan %s" %
                       (self.tcpHost, self.statHost, self.spanHost))
        self.serviceType = serviceType
        self.tcpLayer = StreamClientLayer(self.tcpHost, self.handlerResponse,
                                          self.collectorTcpHello)

        self.spanLayer = DgramLayer(self.spanHost, None)
        self.packetRoute = {
            PacketType.APPLICATION_SEND: self.handle_default,
            PacketType.APPLICATION_TRACE_SEND: self.handle_default,
            PacketType.APPLICATION_TRACE_SEND_ACK: self.handle_default,
            PacketType.APPLICATION_REQUEST: self.handle_appResponse,
            PacketType.APPLICATION_RESPONSE: self.handle_appliaction_response,
            PacketType.APPLICATION_STREAM_CREATE: self.handle_default,
            PacketType.APPLICATION_STREAM_CREATE_SUCCESS: self.handle_default,
            PacketType.APPLICATION_STREAM_CREATE_FAIL: self.handle_default,
            PacketType.APPLICATION_STREAM_CLOSE: self.handle_default,
            PacketType.APPLICATION_STREAM_PING: self.handle_default,
            PacketType.APPLICATION_STREAM_PONG: self.handle_default,
            PacketType.APPLICATION_STREAM_RESPONSE: self.handle_default,
            PacketType.CONTROL_CLIENT_CLOSE: self.handle_default,
            PacketType.CONTROL_SERVER_CLOSE: self.handle_default,
            PacketType.CONTROL_HANDSHAKE: self.handle_default,
            PacketType.CONTROL_HANDSHAKE_RESPONSE:
            self.handle_handshake_response,
            PacketType.CONTROL_PING_SIMPLE: self.handle_control_ping,
            PacketType.CONTROL_PONG: self.handle_recv_pong
        }
        self.socketCode = AgentSocketCode.NONE
        self.startTimeStamp = self.ac.startTimestamp
        self.agentName = app_name
        self.agentInfo = TAgentInfo(agentId=app_id,
                                    applicationName=app_name,
                                    agentVersion=ac.version,
                                    startTimestamp=self.startTimeStamp,
                                    serviceType=self.serviceType,
                                    pid=os.getpid())

        self.agentState = ThriftAgentStateManager(self.app_id,
                                                  self.startTimeStamp,
                                                  self.statHost)
        self.postponed_queue = []
        self.scanLocalInfo()
        self.api_metas = {}
        self.string_metas = {}
        self.span_factory = ThriftSpanFactory(self)
class ThriftAgentImplement(PinpointAgent):
    PingCount = 0
    ReqCount = 0

    def __init__(self, ac, app_id, app_name, serviceType=PHP):

        super().__init__(app_id, app_name)
        self.ac = ac
        self.tcpHost = (ac.CollectorAgentIp, ac.CollectorAgentPort)
        self.statHost = (ac.CollectorStatIp, ac.CollectorStatPort)
        self.spanHost = (ac.CollectorSpanIp, ac.CollectorSpanPort)
        TCLogger.debug("CollectorTcp %s CollectorStat %s CollectorSpan %s" %
                       (self.tcpHost, self.statHost, self.spanHost))
        self.serviceType = serviceType
        self.tcpLayer = StreamClientLayer(self.tcpHost, self.handlerResponse,
                                          self.collectorTcpHello)

        self.spanLayer = DgramLayer(self.spanHost, None)
        self.packetRoute = {
            PacketType.APPLICATION_SEND: self.handle_default,
            PacketType.APPLICATION_TRACE_SEND: self.handle_default,
            PacketType.APPLICATION_TRACE_SEND_ACK: self.handle_default,
            PacketType.APPLICATION_REQUEST: self.handle_appResponse,
            PacketType.APPLICATION_RESPONSE: self.handle_appliaction_response,
            PacketType.APPLICATION_STREAM_CREATE: self.handle_default,
            PacketType.APPLICATION_STREAM_CREATE_SUCCESS: self.handle_default,
            PacketType.APPLICATION_STREAM_CREATE_FAIL: self.handle_default,
            PacketType.APPLICATION_STREAM_CLOSE: self.handle_default,
            PacketType.APPLICATION_STREAM_PING: self.handle_default,
            PacketType.APPLICATION_STREAM_PONG: self.handle_default,
            PacketType.APPLICATION_STREAM_RESPONSE: self.handle_default,
            PacketType.CONTROL_CLIENT_CLOSE: self.handle_default,
            PacketType.CONTROL_SERVER_CLOSE: self.handle_default,
            PacketType.CONTROL_HANDSHAKE: self.handle_default,
            PacketType.CONTROL_HANDSHAKE_RESPONSE:
            self.handle_handshake_response,
            PacketType.CONTROL_PING_SIMPLE: self.handle_control_ping,
            PacketType.CONTROL_PONG: self.handle_recv_pong
        }
        self.socketCode = AgentSocketCode.NONE
        self.startTimeStamp = self.ac.startTimestamp
        self.agentName = app_name
        self.agentInfo = TAgentInfo(agentId=app_id,
                                    applicationName=app_name,
                                    agentVersion=ac.version,
                                    startTimestamp=self.startTimeStamp,
                                    serviceType=self.serviceType,
                                    pid=os.getpid())

        self.agentState = ThriftAgentStateManager(self.app_id,
                                                  self.startTimeStamp,
                                                  self.statHost)
        self.postponed_queue = []
        self.scanLocalInfo()
        self.api_metas = {}
        self.string_metas = {}
        self.span_factory = ThriftSpanFactory(self)

    ## expose to other modules
    def sendMsgToCollector(self, msg):
        if self.socketCode == AgentSocketCode.NONE:  ## channel not ready
            TCLogger.debug("AgentState not ready,postpone size:%d", len(msg))
            self.postponed_queue.append(msg)
        else:
            ### send backlog
            self._flushPostponed()
            self.tcpLayer.sendData(msg)

    def _flushPostponed(self):
        if len(self.postponed_queue) > 0:
            for m in self.postponed_queue:
                TCLogger.debug("postponed size:%d ", len(m))
                self.tcpLayer.sendData(m[:])
            self.postponed_queue = []

    def updateApiMeta(self, name, api_type=API_DEFAULT):

        if name in self.api_metas:
            return self.api_metas[name]
        else:
            meta = ThriftAPIMeta(name=name,
                                 type=api_type,
                                 agentStartTime=self.startTimeStamp,
                                 agentId=self.app_id,
                                 agentName=self.app_name)
            self.sendMsgToCollector(meta.toPacket().getSerializedData())
            self.api_metas[name] = meta
            return meta

    def sendMeta(self, meta):
        '''

        :param ThriftAPIMeta meta:
        :return:
        '''
        TCLogger.debug("meta: %s", meta.name)
        self.sendMsgToCollector(meta.toPacket().getSerializedData())

    def updateStringMeta(self, name):

        if name in self.string_metas:
            return self.string_metas[name]
        else:

            meta = StringMetaData(agentStartTime=self.startTimeStamp,
                                  agentId=self.app_id,
                                  name=name)
            self.sendMeta(meta)
            self.string_metas[name] = meta
            return meta

    def asynSendSpan(self, stack, body):
        self.sendSpan(stack, body)

    def sendSpan(self, stack, body):
        super().sendSpan(stack, body)

        try:
            tSpan = self.span_factory.makeSpan(stack)
            body = CollectorPro.obj2bin(tSpan, SPAN)
            self.spanLayer.sendData(body)
            TCLogger.debug("send TSpan:%s", tSpan)
        except Exception as e:
            TCLogger.error("exception %s", e)
        return True

    def scanLocalInfo(self):

        self.agentInfo.hostname = agentHost.hostname
        self.agentInfo.ip = agentHost.ip
        self.agentInfo.ports = self.ac.getWebPort()

    def start(self):
        self.tcpLayer.start()
        self.spanLayer.start()

    def stop(self):
        self.ac.clean()
        self.tcpLayer.stop()
        self.spanLayer.stop()

    def handle_default(self, tcp_layer, ptype, header, vBody):
        TCLogger.debug('ptype:%d ignore', ptype)
        return 0

    ## APPLICATION_REQUEST
    def handle_appResponse(self, tcp_layer, ptype, header, vBody):
        TCLogger.debug('ptype:%d ignore', ptype)
        return 0

    def negotiatedDone(self, code, tcp_layer):

        # # register ping

        TrainLayer.registerTimers(self.__sendPing, 10, tcp_layer)
        TCLogger.debug("register send ping ")
        #
        # # register TagentInfo
        TrainLayer.registerTimers(self.__sendAgentInfo, 0, tcp_layer)
        TCLogger.debug("send agentInfo ")

        # check the postponed

        self._flushPostponed()

    ## CONTROL_HANDSHAKE_RESPONSE
    def handle_handshake_response(self, tcp_layer, ptype, header, vBody):
        cbf = ChannelBufferV2(vBody.tobytes())
        cmg = ControlMessageDecoder.decodingControlMessage(cbf)

        if cmg.type == ControlMessage.CONTROL_MESSAGE_MAP:
            code_CM = cmg.data[b'code']
            subCode_CM = cmg.data[b'subCode']
            if code_CM.type == ControlMessage.CONTROL_MESSAGE_LONG and subCode_CM.type == ControlMessage.CONTROL_MESSAGE_LONG:
                code = code_CM.data
                subCode = subCode_CM.data
                TCLogger.debug("code %d subcode %d", code, subCode)
                self.socketCode = HandShakeMessage.getNextStateCode(
                    code, subCode)
                self.negotiatedDone(self.socketCode, tcp_layer)

        return 0

    def handle_appliaction_response(self, tcp_layer, ptype, header, vBody):
        '''

        :param tcp_layer:
        :param ptype:
        :param header:
        :param memoryview vBody:
        :return:
        '''
        type, obj = CollectorPro.bin2obj(vBody)
        TCLogger.debug("response: %s", obj)

    def __getPingPacket(self):
        ## ping context

        pingBuf = struct.pack(
            "!ibb",
            self.socketCode,  # ThriftAgent.PingCount,
            0,
            self.socketCode)

        packet = Packet(hType=PacketType.CONTROL_PING_PAYLOAD, body=pingBuf)
        ThriftAgentImplement.PingCount += 1
        return packet

    ## PacketType.CONTROL_PONG
    def handle_recv_pong(self, tcp_layer, ptype, header, vBody):
        TCLogger.debug("recv pong")
        return 0

    ## PacketType.CONTROL_PING
    def handle_control_ping(self, tcp_layer, ptype, header, vBody):
        ping = Packet(PacketType.CONTROL_PONG)
        tcp_layer.sendData(ping.getSerializedData())
        return 0

    def handlerResponse(self, tcp_layer, view, size):
        '''

        :param memoryview view:
        :param int size:
        :return:
        '''
        offset = 0
        iterPacket = Packet.parseNetByteStream(view, size)
        for packet in iterPacket:
            offset, ptype, header, vBody = packet
            self.packetRoute[ptype](tcp_layer, ptype, header, vBody)

        return 0

    def __sendPing(self, tcp_layer):
        ping_data = self.__getPingPacket().getSerializedData()
        tcp_layer.sendData(ping_data)

    def __sendAgentInfo(self, tcp_layer):
        agent_data = self.__getTAgentInfoPacket().getSerializedData()
        tcp_layer.sendData(agent_data)
        TCLogger.debug("send agentInfo len:%d", len(agent_data))

    def collectorTcpHello(self, tcp_layer):
        '''
        :param StreamClientLayer tcp_layer:
        :return:
        '''
        ### handshakepacket
        data = self.__getHandShakePacket(tcp_layer).getSerializedData()
        tcp_layer.sendData(data)
        TCLogger.debug("send hand shake len:%d", len(data))

    def __getHandShakePacket(self, tcp_layer):
        cmp = HandShakeMessage(tcp_layer.getRawSocketFd(),
                               self.agentInfo.hostname, True,
                               self.agentInfo.ip, self.agentInfo.agentId,
                               self.agentInfo.applicationName,
                               self.serviceType, self.agentInfo.pid,
                               self.agentInfo.agentVersion,
                               self.startTimeStamp)

        packet = Packet(PacketType.CONTROL_HANDSHAKE, 0, cmp.getDataLen(),
                        cmp.getBinData())
        return packet

    def __getTAgentInfoPacket(self):
        # self.agentInfo
        TCLogger.debug("agent:%s", self.agentInfo)
        body = CollectorPro.obj2bin(self.agentInfo, AGENT_INFO)
        packet = Packet(PacketType.APPLICATION_REQUEST,
                        CollectorPro.getCurReqCount(), len(body), body)
        ThriftAgentImplement.ReqCount += 1

        return packet