diff --git a/src/api/docs/content/specs/history.yaml b/src/api/docs/content/specs/history.yaml index 4d476665..099b8caa 100644 --- a/src/api/docs/content/specs/history.yaml +++ b/src/api/docs/content/specs/history.yaml @@ -62,7 +62,13 @@ components: - Metrics operationId: "get_client_metrics" description: | - Request data needed to generate the \"Client activity over last 24 hours\" graph + Request data needed to generate the \"Client activity over last 24 hours\" graph. + This endpoint returns the top N clients, sorted by total number of queries within 24 hours. If N is set to 0, all clients will be returned. + The client name is only available if the client's IP address can be resolved to a hostname. + + The last client returned is a special client that contains the total number of queries that were not sent by any of the other shown clients , i.e. queries that were sent by clients that are not in the top N. This client is always present, even if it has 0 queries and can be identified by the special name "other clients" (mind the space in the hostname) and the IP address "0.0.0.0". + + Note that, due to privacy settings, the returned data may also be empty. parameters: - $ref: 'history.yaml#/components/parameters/clients/N' responses: @@ -164,11 +170,15 @@ components: - 12 - 65 - 67 + - 9 + - 5 - timestamp: 1511820500.583821 data: - 1 - 35 - 63 + - 20 + - 9 clients: type: array description: Data array @@ -195,6 +205,12 @@ components: - name: null ip: "192.168.1.1" total: 254 + - name: "pi.hole" + ip: "::" + total: 29 + - name: "other clients" + ip: "0.0.0.0" + total: 14 parameters: clients: N: diff --git a/src/api/history.c b/src/api/history.c index 51ff712a..dfc1014a 100644 --- a/src/api/history.c +++ b/src/api/history.c @@ -138,8 +138,8 @@ int api_history_clients(struct ftl_conn *api) // Get client pointer const clientsData* client = getClient(clientID, true); - // Skip invalid clients and also those managed by alias clients - if(client == NULL || skipclient[clientID]) + // Skip invalid clients + if(client == NULL) continue; // Store clientID and number of queries in temporary array @@ -152,6 +152,7 @@ int api_history_clients(struct ftl_conn *api) // Main return loop cJSON *history = JSON_NEW_ARRAY(); + int others_total = 0; for(unsigned int slot = 0; slot < OVERTIME_SLOTS; slot++) { cJSON *item = JSON_NEW_OBJECT(); @@ -159,7 +160,8 @@ int api_history_clients(struct ftl_conn *api) // Loop over clients to generate output to be sent to the client cJSON *data = JSON_NEW_ARRAY(); - for(unsigned int id = 0; id < Nc; id++) + int others = 0; + for(int id = 0; id < counters->clients; id++) { // Get client pointer const int clientID = temparray[2*id + 0]; @@ -169,8 +171,20 @@ int api_history_clients(struct ftl_conn *api) if(client == NULL) continue; + // Skip clients which should be hidden and add them to the "others" counter. + // Also skip clients when we reached the maximum number of clients to return + if(skipclient[clientID] || id >= (int)Nc) + { + others += client->overTime[slot]; + continue; + } + JSON_ADD_NUMBER_TO_ARRAY(data, client->overTime[slot]); } + // Add others as last element in the array + others_total += others; + JSON_ADD_NUMBER_TO_ARRAY(data, others); + JSON_ADD_ITEM_TO_OBJECT(item, "data", data); JSON_ADD_ITEM_TO_ARRAY(history, item); } @@ -179,7 +193,7 @@ int api_history_clients(struct ftl_conn *api) // Loop over clients to generate output to be sent to the client cJSON *clients = JSON_NEW_ARRAY(); - for(unsigned int id = 0; id < Nc; id++) + for(int id = 0; id < counters->clients; id++) { // Get client pointer const int clientID = temparray[2*id + 0]; @@ -189,6 +203,11 @@ int api_history_clients(struct ftl_conn *api) if(client == NULL) continue; + // Skip clients which should be hidden. Also skip clients when + // we reached the maximum number of clients to return + if(skipclient[clientID] || id >= (int)Nc) + continue; + // Get client name and IP address const char *client_ip = getstr(client->ippos); const char *client_name = client->namepos != 0 ? getstr(client->namepos) : NULL; @@ -201,6 +220,13 @@ int api_history_clients(struct ftl_conn *api) JSON_ADD_ITEM_TO_ARRAY(clients, item); } + // Add "others" client + cJSON *item = JSON_NEW_OBJECT(); + JSON_REF_STR_IN_OBJECT(item, "name", "other clients"); + JSON_REF_STR_IN_OBJECT(item, "ip", "0.0.0.0"); + JSON_ADD_NUMBER_TO_OBJECT(item, "total", others_total); + JSON_ADD_ITEM_TO_ARRAY(clients, item); + // Unlock already here to avoid keeping the lock during JSON generation // This is safe because we don't access any shared memory after this // point and all strings in the JSON are references to idempotent shared