浏览代码

alignment with cspot

Philippe G 3 年之前
父节点
当前提交
662962ddb1

+ 1 - 0
components/spotify/cspot/bell/include/BaseHTTPServer.h

@@ -53,6 +53,7 @@ struct HTTPResponse {
     bool useGzip = false;
     std::string body;
     std::string contentType;
+    std::vector<std::string> extraHeaders = std::vector<std::string>();
     std::unique_ptr<ResponseReader> responseReader;
 };
 

+ 1 - 0
components/spotify/cspot/bell/include/HTTPServer.h

@@ -62,6 +62,7 @@ namespace bell
 
         void registerHandler(RequestType requestType, const std::string &, httpHandler);
         void respond(const HTTPResponse &);
+        void redirectTo(const std::string&, int connectionFd);
         void publishEvent(std::string eventName, std::string eventData);
         void closeConnection(int connection);
         void listen();

+ 1 - 0
components/spotify/cspot/bell/include/Task.h

@@ -3,6 +3,7 @@
 
 #ifdef ESP_PLATFORM
 #include <esp_pthread.h>
+#include <esp_task.h>
 #include <freertos/FreeRTOS.h>
 #include <freertos/timers.h>
 #include <freertos/task.h>

+ 1 - 0
components/spotify/cspot/bell/include/platform/WrappedSemaphore.h

@@ -7,6 +7,7 @@
 #elif __APPLE__
 #include <dispatch/dispatch.h>
 #else
+#include <time.h>
 #include <semaphore.h>
 #endif
 

+ 150 - 184
components/spotify/cspot/bell/src/HTTPServer.cpp

@@ -1,51 +1,37 @@
 #include "HTTPServer.h"
 
-bell::HTTPServer::HTTPServer(int serverPort)
-{
-    this->serverPort = serverPort;
-}
+bell::HTTPServer::HTTPServer(int serverPort) { this->serverPort = serverPort; }
 
-unsigned char bell::HTTPServer::h2int(char c)
-{
-    if (c >= '0' && c <= '9')
-    {
+unsigned char bell::HTTPServer::h2int(char c) {
+    if (c >= '0' && c <= '9') {
         return ((unsigned char)c - '0');
     }
-    if (c >= 'a' && c <= 'f')
-    {
+    if (c >= 'a' && c <= 'f') {
         return ((unsigned char)c - 'a' + 10);
     }
-    if (c >= 'A' && c <= 'F')
-    {
+    if (c >= 'A' && c <= 'F') {
         return ((unsigned char)c - 'A' + 10);
     }
     return (0);
 }
 
-std::string bell::HTTPServer::urlDecode(std::string str)
-{
+std::string bell::HTTPServer::urlDecode(std::string str) {
     std::string encodedString = "";
     char c;
     char code0;
     char code1;
-    for (int i = 0; i < str.length(); i++)
-    {
+    for (int i = 0; i < str.length(); i++) {
         c = str[i];
-        if (c == '+')
-        {
+        if (c == '+') {
             encodedString += ' ';
-        }
-        else if (c == '%')
-        {
+        } else if (c == '%') {
             i++;
             code0 = str[i];
             i++;
             code1 = str[i];
             c = (h2int(code0) << 4) | h2int(code1);
             encodedString += c;
-        }
-        else
-        {
+        } else {
 
             encodedString += c;
         }
@@ -54,23 +40,22 @@ std::string bell::HTTPServer::urlDecode(std::string str)
     return encodedString;
 }
 
-std::vector<std::string> bell::HTTPServer::splitUrl(const std::string &url, char delimiter)
-{
+std::vector<std::string> bell::HTTPServer::splitUrl(const std::string &url,
+                                                    char delimiter) {
     std::stringstream ssb(url);
     std::string segment;
     std::vector<std::string> seglist;
 
-    while (std::getline(ssb, segment, delimiter))
-    {
+    while (std::getline(ssb, segment, delimiter)) {
         seglist.push_back(segment);
     }
     return seglist;
 }
 
-void bell::HTTPServer::registerHandler(RequestType requestType, const std::string &routeUrl, httpHandler handler)
-{
-    if (routes.find(routeUrl) == routes.end())
-    {
+void bell::HTTPServer::registerHandler(RequestType requestType,
+                                       const std::string &routeUrl,
+                                       httpHandler handler) {
+    if (routes.find(routeUrl) == routes.end()) {
         routes.insert({routeUrl, std::vector<HTTPRoute>()});
     }
     this->routes[routeUrl].push_back(HTTPRoute{
@@ -79,9 +64,9 @@ void bell::HTTPServer::registerHandler(RequestType requestType, const std::strin
     });
 }
 
-void bell::HTTPServer::listen()
-{
-    BELL_LOG(info, "http", "Starting configuration server at port %d", this->serverPort);
+void bell::HTTPServer::listen() {
+    BELL_LOG(info, "http", "Starting configuration server at port %d",
+             this->serverPort);
 
     // setup address
     struct addrinfo hints, *server;
@@ -91,8 +76,8 @@ void bell::HTTPServer::listen()
     hints.ai_flags = AI_PASSIVE;
     getaddrinfo(NULL, std::to_string(serverPort).c_str(), &hints, &server);
 
-    int sockfd = socket(server->ai_family,
-                        server->ai_socktype, server->ai_protocol);
+    int sockfd =
+        socket(server->ai_family, server->ai_socktype, server->ai_protocol);
     struct sockaddr_in clientname;
     socklen_t incomingSockSize;
     int i;
@@ -104,12 +89,12 @@ void bell::HTTPServer::listen()
     FD_ZERO(&activeFdSet);
     FD_SET(sockfd, &activeFdSet);
 
-    for (;;)
-    {
+    for (;;) {
         /* Block until input arrives on one or more active sockets. */
         readFdSet = activeFdSet;
-        if (select(FD_SETSIZE, &readFdSet, NULL, NULL, NULL) < 0)
-        {
+        struct timeval tv = {0, 100000};
+
+        if (select(FD_SETSIZE, &readFdSet, NULL, NULL, &tv) < 0) {
             BELL_LOG(error, "http", "Error in select");
             perror("select");
             // exit(EXIT_FAILURE);
@@ -117,118 +102,101 @@ void bell::HTTPServer::listen()
 
         /* Service all the sockets with input pending. */
         for (i = 0; i < FD_SETSIZE; ++i)
-            if (FD_ISSET(i, &readFdSet))
-            {
-                if (i == sockfd)
-                {
+            if (FD_ISSET(i, &readFdSet)) {
+                if (i == sockfd) {
                     /* Connection request on original socket. */
                     int newFd;
                     incomingSockSize = sizeof(clientname);
-                    newFd = accept(sockfd, (struct sockaddr *)&clientname, &incomingSockSize);
-                    if (newFd < 0)
-                    {
+                    newFd = accept(sockfd, (struct sockaddr *)&clientname,
+                                   &incomingSockSize);
+                    if (newFd < 0) {
                         perror("accept");
                         exit(EXIT_FAILURE);
                     }
 
                     FD_SET(newFd, &activeFdSet);
 
-                    HTTPConnection conn = {
-                        .buffer = std::vector<uint8_t>(128),
-                        .httpMethod = ""};
+                    HTTPConnection conn = {.buffer = std::vector<uint8_t>(128),
+                                           .httpMethod = ""};
 
                     this->connections.insert({newFd, conn});
-                }
-                else
-                {
+                } else {
                     /* Data arriving on an already-connected socket. */
                     readFromClient(i);
                 }
             }
 
-        for (auto it = this->connections.cbegin(); it != this->connections.cend() /* not hoisted */; /* no increment */)
-        {
-            if ((*it).second.toBeClosed)
-            {
+        for (auto it = this->connections.cbegin();
+             it != this->connections.cend() /* not hoisted */;
+             /* no increment */) {
+            if ((*it).second.toBeClosed) {
                 close((*it).first);
                 FD_CLR((*it).first, &activeFdSet);
-                this->connections.erase(it++); // or "it = m.erase(it)" since C++11
-            }
-            else
-            {
+                this->connections.erase(
+                    it++); // or "it = m.erase(it)" since C++11
+            } else {
                 ++it;
             }
         }
     }
 }
 
-void bell::HTTPServer::readFromClient(int clientFd)
-{
+void bell::HTTPServer::readFromClient(int clientFd) {
     HTTPConnection &conn = this->connections[clientFd];
 
     int nbytes = recv(clientFd, &conn.buffer[0], conn.buffer.size(), 0);
-    if (nbytes < 0)
-    {
+    if (nbytes < 0) {
         BELL_LOG(error, "http", "Error reading from client");
         perror("recv");
         this->closeConnection(clientFd);
-    }
-    else if (nbytes == 0)
-    {
+    } else if (nbytes == 0) {
         this->closeConnection(clientFd);
-    }
-    else
-    {
-        conn.currentLine += std::string(conn.buffer.data(), conn.buffer.data() + nbytes);
+    } else {
+        conn.currentLine +=
+            std::string(conn.buffer.data(), conn.buffer.data() + nbytes);
     READBODY:
-        if (!conn.isReadingBody)
-        {
-            while (conn.currentLine.find("\r\n") != std::string::npos)
-            {
-                auto line = conn.currentLine.substr(0, conn.currentLine.find("\r\n"));
-                conn.currentLine = conn.currentLine.substr(conn.currentLine.find("\r\n") + 2, conn.currentLine.size());
-                if (line.find("GET ") != std::string::npos || line.find("POST ") != std::string::npos || line.find("OPTIONS ") != std::string::npos)
-                {
+        if (!conn.isReadingBody) {
+            while (conn.currentLine.find("\r\n") != std::string::npos) {
+                auto line =
+                    conn.currentLine.substr(0, conn.currentLine.find("\r\n"));
+                conn.currentLine = conn.currentLine.substr(
+                    conn.currentLine.find("\r\n") + 2, conn.currentLine.size());
+                if (line.find("GET ") != std::string::npos ||
+                    line.find("POST ") != std::string::npos ||
+                    line.find("OPTIONS ") != std::string::npos) {
                     conn.httpMethod = line;
                 }
 
-                if (line.find("Content-Length: ") != std::string::npos)
-                {
-                    conn.contentLength = std::stoi(line.substr(16, line.size() - 1));
-                    BELL_LOG(info, "http", "Content-Length: %d", conn.contentLength);
+                if (line.find("Content-Length: ") != std::string::npos) {
+                    conn.contentLength =
+                        std::stoi(line.substr(16, line.size() - 1));
+                    BELL_LOG(info, "http", "Content-Length: %d",
+                             conn.contentLength);
                 }
-                if (line.size() == 0)
-                {
-                    if (conn.contentLength != 0)
-                    {
+                if (line.size() == 0) {
+                    if (conn.contentLength != 0) {
                         conn.isReadingBody = true;
                         goto READBODY;
-                    }
-                    else
-                    {
-                        findAndHandleRoute(conn.httpMethod, conn.currentLine, clientFd);
+                    } else {
+                        findAndHandleRoute(conn.httpMethod, conn.currentLine,
+                                           clientFd);
                     }
                 }
             }
-        }
-        else
-        {
-            if (conn.currentLine.size() >= conn.contentLength)
-            {
+        } else {
+            if (conn.currentLine.size() >= conn.contentLength) {
                 findAndHandleRoute(conn.httpMethod, conn.currentLine, clientFd);
             }
         }
     }
 }
 
-void bell::HTTPServer::closeConnection(int connection)
-{
+void bell::HTTPServer::closeConnection(int connection) {
 
     this->connections[connection].toBeClosed = true;
 }
 
-void bell::HTTPServer::writeResponseEvents(int connFd)
-{
+void bell::HTTPServer::writeResponseEvents(int connFd) {
     std::lock_guard lock(this->responseMutex);
 
     std::stringstream stream;
@@ -238,8 +206,10 @@ void bell::HTTPServer::writeResponseEvents(int connFd)
     stream << "Content-type: text/event-stream\r\n";
     stream << "Cache-Control: no-cache\r\n";
     stream << "Access-Control-Allow-Origin: *\r\n";
-    stream << "Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS\r\n";
-    stream << "Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token\r\n";
+    stream << "Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, "
+              "OPTIONS\r\n";
+    stream << "Access-Control-Allow-Headers: Origin, Content-Type, "
+              "X-Auth-Token\r\n";
     stream << "\r\n";
 
     auto responseStr = stream.str();
@@ -248,14 +218,12 @@ void bell::HTTPServer::writeResponseEvents(int connFd)
     this->connections[connFd].isEventConnection = true;
 }
 
-void bell::HTTPServer::writeResponse(const HTTPResponse &response)
-{
+void bell::HTTPServer::writeResponse(const HTTPResponse &response) {
     std::lock_guard lock(this->responseMutex);
 
     auto fileSize = response.body.size();
 
-    if (response.responseReader != nullptr)
-    {
+    if (response.responseReader != nullptr) {
         fileSize = response.responseReader->getTotalSize();
     }
 
@@ -265,20 +233,25 @@ void bell::HTTPServer::writeResponse(const HTTPResponse &response)
     stream << "Connection: close\r\n";
     stream << "Content-type: " << response.contentType << "\r\n";
 
-    if (response.useGzip)
-    {
+    if (response.useGzip) {
         stream << "Content-encoding: gzip"
                << "\r\n";
     }
 
-    stream << "Content-length:" << fileSize << "\r\n";
     stream << "Access-Control-Allow-Origin: *\r\n";
-    stream << "Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS\r\n";
-    stream << "Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token\r\n";
+    stream << "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS\r\n";
+    stream << "Access-Control-Expose-Headers: Location\r\n";
+    stream << "Access-Control-Allow-Headers: Origin, Content-Type, "
+              "X-Auth-Token\r\n";
+
+    // go over every item in request->extraHeaders
+    for (auto &header : response.extraHeaders) {
+        stream << header << "\r\n";
+    }
+
     stream << "\r\n";
 
-    if (response.body.size() > 0)
-    {
+    if (response.body.size() > 0) {
         stream << response.body;
     }
 
@@ -286,28 +259,40 @@ void bell::HTTPServer::writeResponse(const HTTPResponse &response)
 
     write(response.connectionFd, responseStr.c_str(), responseStr.size());
 
-    if (response.responseReader != nullptr)
-    {
+    if (response.responseReader != nullptr) {
         size_t read;
-        do
-        {
-            read = response.responseReader->read(responseBuffer.data(), responseBuffer.size());
-            if (read > 0)
-            {
+        do {
+            read = response.responseReader->read(responseBuffer.data(),
+                                                 responseBuffer.size());
+            if (read > 0) {
                 write(response.connectionFd, responseBuffer.data(), read);
             }
         } while (read > 0);
     }
+
+    BELL_LOG(info, "HTTP", "Closing connection");
     this->closeConnection(response.connectionFd);
 }
 
-void bell::HTTPServer::respond(const HTTPResponse &response)
-{
+void bell::HTTPServer::respond(const HTTPResponse &response) {
     writeResponse(response);
 }
 
-void bell::HTTPServer::publishEvent(std::string eventName, std::string eventData)
-{
+void bell::HTTPServer::redirectTo(const std::string & url, int connectionFd) {
+    std::lock_guard lock(this->responseMutex);
+    std::stringstream stream;
+    stream << "HTTP/1.1 301 Moved Permanently\r\n";
+    stream << "Server: EUPHONIUM\r\n";
+    stream << "Connection: close\r\n";
+    stream << "Location: " << url << "\r\n\r\n";
+    auto responseStr = stream.str();
+
+    write(connectionFd, responseStr.c_str(), responseStr.size());
+    this->closeConnection(connectionFd);
+}
+
+void bell::HTTPServer::publishEvent(std::string eventName,
+                                    std::string eventData) {
     std::lock_guard lock(this->responseMutex);
     BELL_LOG(info, "http", "Publishing event");
 
@@ -317,27 +302,24 @@ void bell::HTTPServer::publishEvent(std::string eventName, std::string eventData
     auto responseStr = stream.str();
 
     // Reply to all event-connections
-    for (auto it = this->connections.cbegin(); it != this->connections.cend(); ++it)
-    {
-        if ((*it).second.isEventConnection)
-        {
+    for (auto it = this->connections.cbegin(); it != this->connections.cend();
+         ++it) {
+        if ((*it).second.isEventConnection) {
             write(it->first, responseStr.c_str(), responseStr.size());
         }
     }
 }
 
-std::map<std::string, std::string> bell::HTTPServer::parseQueryString(const std::string &queryString)
-{
+std::map<std::string, std::string>
+bell::HTTPServer::parseQueryString(const std::string &queryString) {
     std::map<std::string, std::string> query;
     auto prefixedString = "&" + queryString;
-    while (prefixedString.find("&") != std::string::npos)
-    {
+    while (prefixedString.find("&") != std::string::npos) {
         auto keyStart = prefixedString.find("&");
         auto keyEnd = prefixedString.find("=");
         // Find second occurence of "&" in prefixedString
         auto valueEnd = prefixedString.find("&", keyStart + 1);
-        if (valueEnd == std::string::npos)
-        {
+        if (valueEnd == std::string::npos) {
             valueEnd = prefixedString.size();
         }
 
@@ -350,13 +332,13 @@ std::map<std::string, std::string> bell::HTTPServer::parseQueryString(const std:
     return query;
 }
 
-void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body, int connectionFd)
-{
+void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body,
+                                          int connectionFd) {
     std::map<std::string, std::string> pathParams;
     std::map<std::string, std::string> queryParams;
+    BELL_LOG(info, "http", "URL %s", url.c_str());
 
-    if (url.find("OPTIONS /") != std::string::npos)
-    {
+    if (url.find("OPTIONS /") != std::string::npos) {
         std::stringstream stream;
         stream << "HTTP/1.1 200 OK\r\n";
         stream << "Server: EUPHONIUM\r\n";
@@ -364,7 +346,8 @@ void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body, i
         stream << "Connection: close\r\n";
         stream << "Access-Control-Allow-Origin: *\r\n";
         stream << "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n";
-        stream << "Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token\r\n";
+        stream << "Access-Control-Allow-Headers: Origin, Content-Type, "
+                  "X-Auth-Token\r\n";
         stream << "\r\n";
 
         auto responseStr = stream.str();
@@ -374,36 +357,29 @@ void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body, i
         return;
     }
 
-    if (url.find("GET /events") != std::string::npos)
-    {
+    if (url.find("GET /events") != std::string::npos) {
         // Handle SSE endpoint here
         writeResponseEvents(connectionFd);
         return;
     }
 
-    for (const auto &routeSet : this->routes)
-    {
-        for (const auto &route : routeSet.second)
-        {
+    for (const auto &routeSet : this->routes) {
+        for (const auto &route : routeSet.second) {
 
             std::string path = url;
-            if (url.find("GET ") != std::string::npos && route.requestType == RequestType::GET)
-            {
+            if (url.find("GET ") != std::string::npos &&
+                route.requestType == RequestType::GET) {
                 path = path.substr(4);
-            }
-            else if (url.find("POST ") != std::string::npos && route.requestType == RequestType::POST)
-            {
+            } else if (url.find("POST ") != std::string::npos &&
+                       route.requestType == RequestType::POST) {
                 path = path.substr(5);
-            }
-            else
-            {
+            } else {
                 continue;
             }
 
             path = path.substr(0, path.find(" "));
 
-            if (path.find("?") != std::string::npos)
-            {
+            if (path.find("?") != std::string::npos) {
                 auto urlEncodedSplit = splitUrl(path, '?');
                 path = urlEncodedSplit[0];
                 queryParams = this->parseQueryString(urlEncodedSplit[1]);
@@ -415,46 +391,36 @@ void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body, i
 
             pathParams.clear();
 
-            if (routeSplit.size() == urlSplit.size())
-            {
-                for (int x = 0; x < routeSplit.size(); x++)
-                {
-                    if (routeSplit[x] != urlSplit[x])
-                    {
-                        if (routeSplit[x][0] == ':')
-                        {
-                            pathParams.insert({routeSplit[x].substr(1), urlSplit[x]});
-                        }
-                        else
-                        {
+            if (routeSplit.size() == urlSplit.size()) {
+                for (int x = 0; x < routeSplit.size(); x++) {
+                    if (routeSplit[x] != urlSplit[x]) {
+                        if (routeSplit[x][0] == ':') {
+                            pathParams.insert(
+                                {routeSplit[x].substr(1), urlSplit[x]});
+                        } else {
                             matches = false;
                         }
                     }
                 }
-            }
-            else
-            {
+            } else {
                 matches = false;
             }
 
-            if (routeSplit.back().find("*") != std::string::npos && urlSplit[1] == routeSplit[1])
-            {
+            if (routeSplit.back().find("*") != std::string::npos &&
+                urlSplit[1] == routeSplit[1]) {
                 matches = true;
             }
 
-            if (matches)
-            {
-                if (body.find("&") != std::string::npos)
-                {
+            if (matches) {
+                if (body.find("&") != std::string::npos) {
                     queryParams = this->parseQueryString(body);
                 }
 
-                HTTPRequest req = {
-                    .urlParams = pathParams,
-                    .queryParams = queryParams,
-                    .body = body,
-                    .handlerId = 0,
-                    .connection = connectionFd};
+                HTTPRequest req = {.urlParams = pathParams,
+                                   .queryParams = queryParams,
+                                   .body = body,
+                                   .handlerId = 0,
+                                   .connection = connectionFd};
 
                 route.handler(req);
                 return;

+ 1 - 0
components/spotify/cspot/src/AudioChunkManager.cpp

@@ -114,6 +114,7 @@ void AudioChunkManager::runTask() {
             } catch (...) {
             }
         } else {
+//            usleep(100*1000);
         }
     }
 

+ 1 - 1
components/spotify/cspot/src/MercuryManager.cpp

@@ -9,7 +9,7 @@ std::map<MercuryType, std::string> MercuryTypeMap({
     {MercuryType::UNSUB, "UNSUB"},
     });
 
-MercuryManager::MercuryManager(std::unique_ptr<Session> session): bell::Task("mercuryManager", 8 * 1024, +1, 1)
+MercuryManager::MercuryManager(std::unique_ptr<Session> session): bell::Task("mercuryManager", 6 * 1024, +1, 1)
 {
     this->timeProvider = std::make_shared<TimeProvider>();
     this->callbacks = std::map<uint64_t, mercuryCallback>();

+ 4 - 1
components/spotify/cspot/src/PlainConnection.cpp

@@ -5,7 +5,10 @@
 #include <errno.h>
 #include "Logger.h"
 
-PlainConnection::PlainConnection(){};
+PlainConnection::PlainConnection()
+{
+	this->apSock = -1;
+};
 
 PlainConnection::~PlainConnection()
 {

+ 2 - 0
components/spotify/cspot/src/Player.cpp

@@ -83,6 +83,8 @@ void Player::runTask()
             currentTrack->audioStream->streamFinishedCallback = nullptr;
             currentTrack->audioStream->audioSink = nullptr;
             currentTrack->audioStream->pcmCallback = nullptr;
+        } else {
+            //usleep(100000);
         }
     }
 }