1.
class HTTP2Transport
: public TransportInterface
, public PostConnectObserverInterface
, public PostConnectSendMessageInterface
, public std::enable_shared_from_this<HTTP2Transport> {
bool connect() override;
}
overide(重写)基类的成员函数,派生类重定义基类的虚函数,即会覆盖基类的虚函数,参考overload(重载),new(重定义)
std::shared_ptr<alexaClientSDK::authDelegate::AuthDelegate> authDelegate =
alexaClientSDK::authDelegate::AuthDelegate::create();
authDelegate 的实例过程会初始化一个httppost实例,authDelegate 的初始化会用httppost去请求refresh token;
bool AuthDelegate::init() {
m_refreshAndNotifyThread = std::thread(&AuthDelegate::refreshAndNotifyThreadFunction, this);
}
//完成refresh token的获取成功
client->connect(endpoint);
=>
void AVSConnectionManager::enable() {
m_isEnabled = true;
m_messageRouter->enable();
}
=>
void MessageRouter::enable() {
//通知观察者状态更新
setConnectionStatusLocked();
//HTTP2Transport::create(),connect服务器
createActiveTransportLocked();
}
void MessageRouter::createActiveTransportLocked() {
//http2transport的初始化,
auto transport =
createTransport(m_authDelegate, m_attachmentManager, m_avsEndpoint, shared_from_this(), shared_from_this());
if (transport && transport->connect()) {
m_transports.push_back(transport);
m_activeTransport = transport;
} else {
safelyResetActiveTransportLocked();
setConnectionStatusLocked(
ConnectionStatusObserverInterface::Status::DISCONNECTED,
ConnectionStatusObserverInterface::ChangedReason::INTERNAL_ERROR);
ACSDK_ERROR(
LX("createActiveTransportLockedFailed").d("reason", transport ? "internalError" : "createTransportFailed"));
}
}
bool HTTP2Transport::connect() {
m_multi = avsCommon::utils::libcurlUtils::CurlMultiHandleWrapper::create();
if (curl_multi_setopt(m_multi->getCurlHandle(), CURLMOPT_PIPELINING, 2L) != CURLM_OK)
1) setupDownchannelStream(&reason);
2) m_postConnectObject->doPostConnect(shared_from_this());
3) m_networkThread = std::thread(&HTTP2Transport::networkLoop, this);
}
1) 设置DownchannelStream
bool HTTP2Transport::setupDownchannelStream(ConnectionStatusObserverInterface::ChangedReason* reason) {
std::string authToken = m_authDelegate->getAuthToken();
std::string url = m_avsEndpoint + AVS_DOWNCHANNEL_URL_PATH_EXTENSION;
m_downchannelStream = m_streamPool.createGetStream(url, authToken, m_messageConsumer);
m_downchannelStream->setConnectionTimeout(ESTABLISH_CONNECTION_TIMEOUT);
m_multi->addHandle(m_downchannelStream->getCurlHandle());
m_activeStreams.insert(ActiveTransferEntry(m_downchannelStream->getCurlHandle(), m_downchannelStream));
}
std::shared_ptr<HTTP2Stream> HTTP2StreamPool::createGetStream() {
stream->initGet(url, authToken);
}
bool HTTP2Stream::initGet(const std::string& url, const std::string& authToken) {
setCommonOptions(url, authToken)() {
m_transfer.setURL(url);
m_transfer.addHTTPHeader(authHeader.str());
m_transfer.setWriteCallback(&HTTP2Stream::writeCallback, this);
m_transfer.setHeaderCallback(&HTTP2Stream::headerCallback, this);
setopt(CURLOPT_TCP_KEEPALIVE, "CURLOPT_TCP_KEEPALIVE", 1);
}
}
2) 监听post是否成功:先更新m_contextManager->getContext,notify线程void ContextManager::updateStatesLoop(),request请求入队列,为downchannel连接成功后,postconnect做准备;
bool PostConnectSynchronizer::doPostConnect(std::shared_ptr<HTTP2Transport> transport) {
m_postConnectThread = std::thread(&PostConnectSynchronizer::postConnectLoop, this);
//监听post是否成功,void HTTP2Transport::cleanupFinishedStreams()函数的观察者会发送
it->second->notifyRequestObserver()-》void HTTP2Stream::notifyRequestObserver()=》
void MessageRequest::sendCompleted()=>void PostConnectSynchronizer::onSendCompleted()
}
void PostConnectSynchronizer::postConnectLoop() {
while (!isStopping() && !isPostConnected()) {
{
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_contextFetchInProgress) {
//notify线程void ContextManager::updateStatesLoop(),细节见备注
PostConnectObject::m_contextManager->getContext(shared_from_this());
m_contextFetchInProgress = true;
}
}
m_wakeRetryTrigger.wait_for(lock, retryBackoff, [this] { return m_isPostConnected || m_isStopping; });
}
}
备注:
requestStatesLocked(stateProviderLock);
=>
void ContextManager::sendContextAndClearQueue()
=>
void PostConnectSynchronizer::onContextAvailable(const std::string& jsonContext) {}
=>
void HTTP2Transport::sendPostConnectMessage(std::shared_ptr<MessageRequest> request) {
enqueueRequest(request, true);
}
题外话:
std::shared_ptr<PostConnectObject> PostConnectObject::create() {
if (!m_contextManager) {
ACSDK_ERROR(LX("postCreateFailed").d("reason", "contextManagerNullData"));
return nullptr;
}
return std::shared_ptr<PostConnectObject>(new PostConnectSynchronizer());
}
std::shared_ptr<HTTP2Transport> HTTP2Transport::create(
std::shared_ptr<AuthDelegateInterface> authDelegate,
const std::string& avsEndpoint,
std::shared_ptr<MessageConsumerInterface> messageConsumerInterface,
std::shared_ptr<AttachmentManager> attachmentManager,
std::shared_ptr<TransportObserverInterface> observer) {
std::shared_ptr<PostConnectObject> postConnectObject = PostConnectObject::create();
if (!postConnectObject) {
ACSDK_ERROR(LX("HTTP2Transport::createFailed").d("reason", "nullPostConnectObject"));
return nullptr;
}
return std::shared_ptr<HTTP2Transport>(new HTTP2Transport(
authDelegate, avsEndpoint, messageConsumerInterface, attachmentManager, postConnectObject, observer));
}
3) m_networkThread = std::thread(&HTTP2Transport::networkLoop, this);
void HTTP2Transport::networkLoop() {
(1)与服务器建连,当收到200退出while循环;
(2)处理response(......)
}
这里介绍下get方式连接服务器,连接成功跳出
这里分析下get,post:
1)networkLoop函数有两个while循环,第一个循环使用m_downchannelStream来完成与服务器的连接,其中m_downchannelStream初始化了initGet,连接服务器后用它来接收指令消息;
2)连接成功后状态更新,networkLoop跳出第一个循环,进入第二个while循环,cleanupFinishedStreams没有查询到downchannel之类的对象对downchannel进行notifyObserversOnServerSideDisconnect
3)在第二个循环中processNextOutgoingMessage=》dequeueRequest获取post connect request请求
-》createPostStream
(!m_transfer.setReadCallback(HTTP2Stream::readCallback, this))
(!setCommonOptions(url, authToken))
downchannel 定义:The downchannel remains open in a half-closed state from the device and open from AVS for the life of the connection. The downchannel is primarily used to send cloud-initiated directives and audio attachments to your client.
1.先通过GET request to /{{API version}}/directives建立downchannel通道;
2.通过POST request to /{{API version}}/events on a new event stream on the existing connection ,至此与服务器建立connect连接;
3.随后的连接如下:
1)Send events to and receive directives from AVS
2)Receive cloud-initiated directives on the downchannel stream
client发起请求的规则:Requests are handled sequentially. Therefore, new requests should be sent after Alexa has started responding to your previous request (once the previous request returns headers).
并发请求规则:
- Your product opens a stream and sends a multipart message consisting of one JSON-formatted event and up to one binary audio attachment (zero or one). For more information, see Structuring an HTTP/2 Request.
- AVS returns multipart messages consisting of one more JSON-formatted directives and corresponding audio attachments on the same stream, potentially before streaming is complete. The url attribute that follows cid: in a Play or Speak directive will also appear in the header of the associated audio attachment.
- Following a response from AVS the event stream should be closed.