From 836b47cb7e99a977c5a23b059ca1d0b5065d310e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 24 Jul 2024 11:54:23 +0200 Subject: Merging upstream version 1.46.3. Signed-off-by: Daniel Baumann --- web/api/badges/web_buffer_svg.c | 1159 --------------------------------------- 1 file changed, 1159 deletions(-) delete mode 100644 web/api/badges/web_buffer_svg.c (limited to 'web/api/badges/web_buffer_svg.c') diff --git a/web/api/badges/web_buffer_svg.c b/web/api/badges/web_buffer_svg.c deleted file mode 100644 index 9b81ba4f..00000000 --- a/web/api/badges/web_buffer_svg.c +++ /dev/null @@ -1,1159 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "web_buffer_svg.h" - -#define BADGE_HORIZONTAL_PADDING 4 -#define VERDANA_KERNING 0.2 -#define VERDANA_PADDING 1.0 - -/* - * verdana11_widths[] has been generated with this method: - * https://github.com/badges/shields/blob/master/measure-text.js -*/ - -static double verdana11_widths[128] = { - [0] = 0.0, - [1] = 0.0, - [2] = 0.0, - [3] = 0.0, - [4] = 0.0, - [5] = 0.0, - [6] = 0.0, - [7] = 0.0, - [8] = 0.0, - [9] = 0.0, - [10] = 0.0, - [11] = 0.0, - [12] = 0.0, - [13] = 0.0, - [14] = 0.0, - [15] = 0.0, - [16] = 0.0, - [17] = 0.0, - [18] = 0.0, - [19] = 0.0, - [20] = 0.0, - [21] = 0.0, - [22] = 0.0, - [23] = 0.0, - [24] = 0.0, - [25] = 0.0, - [26] = 0.0, - [27] = 0.0, - [28] = 0.0, - [29] = 0.0, - [30] = 0.0, - [31] = 0.0, - [32] = 3.8671874999999996, // - [33] = 4.3291015625, // ! - [34] = 5.048828125, // " - [35] = 9.001953125, // # - [36] = 6.9931640625, // $ - [37] = 11.837890625, // % - [38] = 7.992187499999999, // & - [39] = 2.9541015625, // ' - [40] = 4.9951171875, // ( - [41] = 4.9951171875, // ) - [42] = 6.9931640625, // * - [43] = 9.001953125, // + - [44] = 4.00146484375, // , - [45] = 4.9951171875, // - - [46] = 4.00146484375, // . - [47] = 4.9951171875, // / - [48] = 6.9931640625, // 0 - [49] = 6.9931640625, // 1 - [50] = 6.9931640625, // 2 - [51] = 6.9931640625, // 3 - [52] = 6.9931640625, // 4 - [53] = 6.9931640625, // 5 - [54] = 6.9931640625, // 6 - [55] = 6.9931640625, // 7 - [56] = 6.9931640625, // 8 - [57] = 6.9931640625, // 9 - [58] = 4.9951171875, // : - [59] = 4.9951171875, // ; - [60] = 9.001953125, // < - [61] = 9.001953125, // = - [62] = 9.001953125, // > - [63] = 5.99951171875, // ? - [64] = 11.0, // @ - [65] = 7.51953125, // A - [66] = 7.541015625, // B - [67] = 7.680664062499999, // C - [68] = 8.4755859375, // D - [69] = 6.95556640625, // E - [70] = 6.32177734375, // F - [71] = 8.529296875, // G - [72] = 8.26611328125, // H - [73] = 4.6298828125, // I - [74] = 5.00048828125, // J - [75] = 7.62158203125, // K - [76] = 6.123046875, // L - [77] = 9.2705078125, // M - [78] = 8.228515625, // N - [79] = 8.658203125, // O - [80] = 6.63330078125, // P - [81] = 8.658203125, // Q - [82] = 7.6484375, // R - [83] = 7.51953125, // S - [84] = 6.7783203125, // T - [85] = 8.05126953125, // U - [86] = 7.51953125, // V - [87] = 10.87646484375, // W - [88] = 7.53564453125, // X - [89] = 6.767578125, // Y - [90] = 7.53564453125, // Z - [91] = 4.9951171875, // [ - [92] = 4.9951171875, // backslash - [93] = 4.9951171875, // ] - [94] = 9.001953125, // ^ - [95] = 6.9931640625, // _ - [96] = 6.9931640625, // ` - [97] = 6.6064453125, // a - [98] = 6.853515625, // b - [99] = 5.73095703125, // c - [100] = 6.853515625, // d - [101] = 6.552734375, // e - [102] = 3.8671874999999996, // f - [103] = 6.853515625, // g - [104] = 6.9609375, // h - [105] = 3.0185546875, // i - [106] = 3.78662109375, // j - [107] = 6.509765625, // k - [108] = 3.0185546875, // l - [109] = 10.69921875, // m - [110] = 6.9609375, // n - [111] = 6.67626953125, // o - [112] = 6.853515625, // p - [113] = 6.853515625, // q - [114] = 4.6943359375, // r - [115] = 5.73095703125, // s - [116] = 4.33447265625, // t - [117] = 6.9609375, // u - [118] = 6.509765625, // v - [119] = 9.001953125, // w - [120] = 6.509765625, // x - [121] = 6.509765625, // y - [122] = 5.779296875, // z - [123] = 6.982421875, // { - [124] = 4.9951171875, // | - [125] = 6.982421875, // } - [126] = 9.001953125, // ~ - [127] = 0.0 -}; - -// find the width of the string using the verdana 11points font -static inline double verdana11_width(const char *s, float em_size) { - double w = 0.0; - - while(*s) { - // if UTF8 multibyte char found and guess it's width equal 1em - // as label width will be updated with JavaScript this is not so important - - // TODO: maybe move UTF8 functions from url.c to separate util in libnetdata - // then use url_utf8_get_byte_length etc. - if(IS_UTF8_STARTBYTE(*s)) { - s++; - while(IS_UTF8_BYTE(*s) && !IS_UTF8_STARTBYTE(*s)){ - s++; - } - w += em_size; - } - else { - if(likely(!(*s & 0x80))){ // Byte 1XXX XXXX is not valid in UTF8 - double t = verdana11_widths[(unsigned char)*s]; - if(t != 0.0) - w += t + VERDANA_KERNING; - } - s++; - } - } - - w -= VERDANA_KERNING; - w += VERDANA_PADDING; - return w; -} - -static inline size_t escape_xmlz(char *dst, const char *src, size_t len) { - size_t i = len; - - // required escapes from - // https://github.com/badges/shields/blob/master/badge.js - while(*src && i) { - switch(*src) { - case '\\': - *dst++ = '/'; - src++; - i--; - break; - - case '&': - if(i > 5) { - strcpy(dst, "&"); - i -= 5; - dst += 5; - src++; - } - else goto cleanup; - break; - - case '<': - if(i > 4) { - strcpy(dst, "<"); - i -= 4; - dst += 4; - src++; - } - else goto cleanup; - break; - - case '>': - if(i > 4) { - strcpy(dst, ">"); - i -= 4; - dst += 4; - src++; - } - else goto cleanup; - break; - - case '"': - if(i > 6) { - strcpy(dst, """); - i -= 6; - dst += 6; - src++; - } - else goto cleanup; - break; - - case '\'': - if(i > 6) { - strcpy(dst, "'"); - i -= 6; - dst += 6; - src++; - } - else goto cleanup; - break; - - default: - i--; - *dst++ = *src++; - break; - } - } - -cleanup: - *dst = '\0'; - return len - i; -} - -static inline char *format_value_with_precision_and_unit(char *value_string, size_t value_string_len, - NETDATA_DOUBLE value, const char *units, int precision) { - if(unlikely(isnan(value) || isinf(value))) - value = 0.0; - - char *separator = ""; - if(unlikely(isalnum(*units))) - separator = " "; - - if(precision < 0) { - int len, lstop = 0, trim_zeros = 1; - - NETDATA_DOUBLE abs = value; - if(isless(value, 0)) { - lstop = 1; - abs = fabsndd(value); - } - - if(isgreaterequal(abs, 1000)) { - len = snprintfz(value_string, value_string_len, "%0.0" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - trim_zeros = 0; - } - else if(isgreaterequal(abs, 10)) len = snprintfz(value_string, value_string_len, "%0.1" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.2" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else if(isgreaterequal(abs, 0.01)) len = snprintfz(value_string, value_string_len, "%0.4" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else if(isgreaterequal(abs, 0.001)) len = snprintfz(value_string, value_string_len, "%0.5" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else if(isgreaterequal(abs, 0.0001)) len = snprintfz(value_string, value_string_len, "%0.6" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - else len = snprintfz(value_string, value_string_len, "%0.7" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE) value); - - if(unlikely(trim_zeros)) { - int l; - // remove trailing zeros from the decimal part - for(l = len - 1; l > lstop; l--) { - if(likely(value_string[l] == '0')) { - value_string[l] = '\0'; - len--; - } - - else if(unlikely(value_string[l] == '.')) { - value_string[l] = '\0'; - len--; - break; - } - - else - break; - } - } - - if(unlikely(len <= 0)) len = 1; - snprintfz(&value_string[len], value_string_len - len, "%s%s", separator, units); - } - else { - if(precision > 50) precision = 50; - snprintfz(value_string, value_string_len, "%0.*" NETDATA_DOUBLE_MODIFIER "%s%s", precision, (NETDATA_DOUBLE) value, separator, units); - } - - return value_string; -} - -typedef enum badge_units_format { - UNITS_FORMAT_NONE, - UNITS_FORMAT_SECONDS, - UNITS_FORMAT_SECONDS_AGO, - UNITS_FORMAT_MINUTES, - UNITS_FORMAT_MINUTES_AGO, - UNITS_FORMAT_HOURS, - UNITS_FORMAT_HOURS_AGO, - UNITS_FORMAT_ONOFF, - UNITS_FORMAT_UPDOWN, - UNITS_FORMAT_OKERROR, - UNITS_FORMAT_OKFAILED, - UNITS_FORMAT_EMPTY, - UNITS_FORMAT_PERCENT -} UNITS_FORMAT; - - -static struct units_formatter { - const char *units; - uint32_t hash; - UNITS_FORMAT format; -} badge_units_formatters[] = { - { "seconds", 0, UNITS_FORMAT_SECONDS }, - { "seconds ago", 0, UNITS_FORMAT_SECONDS_AGO }, - { "minutes", 0, UNITS_FORMAT_MINUTES }, - { "minutes ago", 0, UNITS_FORMAT_MINUTES_AGO }, - { "hours", 0, UNITS_FORMAT_HOURS }, - { "hours ago", 0, UNITS_FORMAT_HOURS_AGO }, - { "on/off", 0, UNITS_FORMAT_ONOFF }, - { "on-off", 0, UNITS_FORMAT_ONOFF }, - { "onoff", 0, UNITS_FORMAT_ONOFF }, - { "up/down", 0, UNITS_FORMAT_UPDOWN }, - { "up-down", 0, UNITS_FORMAT_UPDOWN }, - { "updown", 0, UNITS_FORMAT_UPDOWN }, - { "ok/error", 0, UNITS_FORMAT_OKERROR }, - { "ok-error", 0, UNITS_FORMAT_OKERROR }, - { "okerror", 0, UNITS_FORMAT_OKERROR }, - { "ok/failed", 0, UNITS_FORMAT_OKFAILED }, - { "ok-failed", 0, UNITS_FORMAT_OKFAILED }, - { "okfailed", 0, UNITS_FORMAT_OKFAILED }, - { "empty", 0, UNITS_FORMAT_EMPTY }, - { "null", 0, UNITS_FORMAT_EMPTY }, - { "percentage", 0, UNITS_FORMAT_PERCENT }, - { "percent", 0, UNITS_FORMAT_PERCENT }, - { "pcent", 0, UNITS_FORMAT_PERCENT }, - - // terminator - { NULL, 0, UNITS_FORMAT_NONE } -}; - -inline char *format_value_and_unit(char *value_string, size_t value_string_len, - NETDATA_DOUBLE value, const char *units, int precision) { - static int max = -1; - int i; - - if(unlikely(max == -1)) { - for(i = 0; badge_units_formatters[i].units; i++) - badge_units_formatters[i].hash = simple_hash(badge_units_formatters[i].units); - - max = i; - } - - if(unlikely(!units)) units = ""; - uint32_t hash_units = simple_hash(units); - - UNITS_FORMAT format = UNITS_FORMAT_NONE; - for(i = 0; i < max; i++) { - struct units_formatter *ptr = &badge_units_formatters[i]; - - if(hash_units == ptr->hash && !strcmp(units, ptr->units)) { - format = ptr->format; - break; - } - } - - if(unlikely(format == UNITS_FORMAT_SECONDS || format == UNITS_FORMAT_SECONDS_AGO)) { - if(value == 0.0) { - snprintfz(value_string, value_string_len, "%s", "now"); - return value_string; - } - else if(isnan(value) || isinf(value)) { - snprintfz(value_string, value_string_len, "%s", "undefined"); - return value_string; - } - - const char *suffix = (format == UNITS_FORMAT_SECONDS_AGO)?" ago":""; - - size_t s = (size_t)value; - size_t d = s / 86400; - s = s % 86400; - - size_t h = s / 3600; - s = s % 3600; - - size_t m = s / 60; - s = s % 60; - - if(d) - snprintfz(value_string, value_string_len, "%zu %s %02zu:%02zu:%02zu%s", d, (d == 1)?"day":"days", h, m, s, suffix); - else - snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix); - - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_MINUTES || format == UNITS_FORMAT_MINUTES_AGO)) { - if(value == 0.0) { - snprintfz(value_string, value_string_len, "%s", "now"); - return value_string; - } - else if(isnan(value) || isinf(value)) { - snprintfz(value_string, value_string_len, "%s", "undefined"); - return value_string; - } - - const char *suffix = (format == UNITS_FORMAT_MINUTES_AGO)?" ago":""; - - size_t m = (size_t)value; - size_t d = m / (60 * 24); - m = m % (60 * 24); - - size_t h = m / 60; - m = m % 60; - - if(d) - snprintfz(value_string, value_string_len, "%zud %02zuh %02zum%s", d, h, m, suffix); - else - snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix); - - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_HOURS || format == UNITS_FORMAT_HOURS_AGO)) { - if(value == 0.0) { - snprintfz(value_string, value_string_len, "%s", "now"); - return value_string; - } - else if(isnan(value) || isinf(value)) { - snprintfz(value_string, value_string_len, "%s", "undefined"); - return value_string; - } - - const char *suffix = (format == UNITS_FORMAT_HOURS_AGO)?" ago":""; - - size_t h = (size_t)value; - size_t d = h / 24; - h = h % 24; - - if(d) - snprintfz(value_string, value_string_len, "%zud %zuh%s", d, h, suffix); - else - snprintfz(value_string, value_string_len, "%zuh%s", h, suffix); - - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_ONOFF)) { - snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off"); - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_UPDOWN)) { - snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down"); - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_OKERROR)) { - snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error"); - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_OKFAILED)) { - snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed"); - return value_string; - } - - else if(unlikely(format == UNITS_FORMAT_EMPTY)) - units = ""; - - else if(unlikely(format == UNITS_FORMAT_PERCENT)) - units = "%"; - - if(unlikely(isnan(value) || isinf(value))) { - strcpy(value_string, "-"); - return value_string; - } - - return format_value_with_precision_and_unit(value_string, value_string_len, value, units, precision); -} - -static struct badge_color { - const char *name; - uint32_t hash; - const char *color; -} badge_colors[] = { - - // colors from: - // https://github.com/badges/shields/blob/master/colorscheme.json - - { "brightgreen", 0, "4c1" }, - { "green", 0, "97CA00" }, - { "yellow", 0, "dfb317" }, - { "yellowgreen", 0, "a4a61d" }, - { "orange", 0, "fe7d37" }, - { "red", 0, "e05d44" }, - { "blue", 0, "007ec6" }, - { "grey", 0, "555" }, - { "gray", 0, "555" }, - { "lightgrey", 0, "9f9f9f" }, - { "lightgray", 0, "9f9f9f" }, - - // terminator - { NULL, 0, NULL } -}; - -static inline const char *color_map(const char *color, const char *def) { - static int max = -1; - int i; - - if(unlikely(max == -1)) { - for(i = 0; badge_colors[i].name ;i++) - badge_colors[i].hash = simple_hash(badge_colors[i].name); - - max = i; - } - - uint32_t hash = simple_hash(color); - - for(i = 0; i < max; i++) { - struct badge_color *ptr = &badge_colors[i]; - - if(hash == ptr->hash && !strcmp(color, ptr->name)) - return ptr->color; - } - - return def; -} - -typedef enum color_comparison { - COLOR_COMPARE_EQUAL, - COLOR_COMPARE_NOTEQUAL, - COLOR_COMPARE_LESS, - COLOR_COMPARE_LESSEQUAL, - COLOR_COMPARE_GREATER, - COLOR_COMPARE_GREATEREQUAL, -} BADGE_COLOR_COMPARISON; - -static inline void calc_colorz(const char *color, char *final, size_t len, NETDATA_DOUBLE value) { - if(isnan(value) || isinf(value)) - value = NAN; - - char color_buffer[256 + 1] = ""; - char value_buffer[256 + 1] = ""; - BADGE_COLOR_COMPARISON comparison = COLOR_COMPARE_GREATER; - - // example input: - // colormin|color:null... - - const char *c = color; - while(*c) { - char *dc = color_buffer, *dv = NULL; - size_t ci = 0, vi = 0; - - const char *t = c; - - while(*t && *t != '|') { - switch(*t) { - case '!': - if(t[1] == '=') t++; - comparison = COLOR_COMPARE_NOTEQUAL; - dv = value_buffer; - break; - - case '=': - case ':': - comparison = COLOR_COMPARE_EQUAL; - dv = value_buffer; - break; - - case '}': - case ')': - case '>': - if(t[1] == '=') { - comparison = COLOR_COMPARE_GREATEREQUAL; - t++; - } - else - comparison = COLOR_COMPARE_GREATER; - dv = value_buffer; - break; - - case '{': - case '(': - case '<': - if(t[1] == '=') { - comparison = COLOR_COMPARE_LESSEQUAL; - t++; - } - else if(t[1] == '>' || t[1] == ')' || t[1] == '}') { - comparison = COLOR_COMPARE_NOTEQUAL; - t++; - } - else - comparison = COLOR_COMPARE_LESS; - dv = value_buffer; - break; - - default: - if(dv) { - if(vi < 256) { - vi++; - *dv++ = *t; - } - } - else { - if(ci < 256) { - ci++; - *dc++ = *t; - } - } - break; - } - - t++; - } - - // prepare for next iteration - if(*t == '|') t++; - c = t; - - // do the math - *dc = '\0'; - if(dv) { - *dv = '\0'; - NETDATA_DOUBLE v; - - if(!*value_buffer || !strcmp(value_buffer, "null")) { - v = NAN; - } - else { - v = str2l(value_buffer); - if(isnan(v) || isinf(v)) - v = NAN; - } - - if(unlikely(isnan(value) || isnan(v))) { - if(isnan(value) && isnan(v)) - break; - } - else { - if (unlikely(comparison == COLOR_COMPARE_LESS && isless(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_LESSEQUAL && islessequal(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_GREATER && isgreater(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_GREATEREQUAL && isgreaterequal(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_EQUAL && !islessgreater(value, v))) break; - else if (unlikely(comparison == COLOR_COMPARE_NOTEQUAL && islessgreater(value, v))) break; - } - } - else - break; - } - - const char *b; - if(color_buffer[0]) - b = color_buffer; - else - b = color; - - strncpyz(final, b, len); -} - -// value + units -#define VALUE_STRING_SIZE 100 - -// label -#define LABEL_STRING_SIZE 200 - -// colors -#define COLOR_STRING_SIZE 100 - -static inline int allowed_hexa_char(char x) { - return ( (x >= '0' && x <= '9') || - (x >= 'a' && x <= 'f') || - (x >= 'A' && x <= 'F') - ); -} - -static int html_color_check(const char *str) { - int i = 0; - while(str[i]) { - if(!allowed_hexa_char(str[i])) - return 0; - if(unlikely(i >= 6)) - return 0; - i++; - } - // want to allow either RGB or RRGGBB - return ( i == 6 || i == 3 ); -} - -// Will parse color arg as #RRGGBB or #RGB or one of the colors -// from color_map hash table -// if parsing fails (argument error) it will return default color -// given as default parameter (def) -// in any case it will return either color in "RRGGBB" or "RGB" format as string -// or whatever is given as def (without checking - caller responsible to give sensible -// safely escaped default) as default if it fails -// in any case this function must always return something we can put directly in XML -// so no escaping is necessary anymore (with exception of default where caller is responsible) -// to give sensible default -#define BADGE_SVG_COLOR_ARG_MAXLEN 20 - -static const char *parse_color_argument(const char *arg, const char *def) -{ - if( !arg ) - return def; - size_t len = strnlen(arg, BADGE_SVG_COLOR_ARG_MAXLEN); - if( len < 2 || len >= BADGE_SVG_COLOR_ARG_MAXLEN ) - return def; - if( html_color_check(arg) ) - return arg; - return color_map(arg, def); -} - -void buffer_svg(BUFFER *wb, const char *label, - NETDATA_DOUBLE value, const char *units, const char *label_color, const char *value_color, int precision, int scale, uint32_t options, int fixed_width_lbl, int fixed_width_val, const char* text_color_lbl, const char* text_color_val) { - char value_color_buffer[COLOR_STRING_SIZE + 1] - , value_string[VALUE_STRING_SIZE + 1] - , label_escaped[LABEL_STRING_SIZE + 1] - , value_escaped[VALUE_STRING_SIZE + 1]; - - const char *label_color_parsed; - const char *value_color_parsed; - - double label_width = (double)fixed_width_lbl, value_width = (double)fixed_width_val, total_width; - double height = 20.0, font_size = 11.0, text_offset = 5.8, round_corner = 3.0; - - if(scale < 100) scale = 100; - - if(unlikely(!value_color || !*value_color)) - value_color = (isnan(value) || isinf(value))?"999":"4c1"; - - calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value); - format_value_and_unit(value_string, VALUE_STRING_SIZE, (options & RRDR_OPTION_DISPLAY_ABS)? fabsndd(value):value, units, precision); - - if(fixed_width_lbl <= 0 || fixed_width_val <= 0) { - label_width = verdana11_width(label, font_size) + (BADGE_HORIZONTAL_PADDING * 2); - value_width = verdana11_width(value_string, font_size) + (BADGE_HORIZONTAL_PADDING * 2); - } - total_width = label_width + value_width; - - escape_xmlz(label_escaped, label, LABEL_STRING_SIZE); - escape_xmlz(value_escaped, value_string, VALUE_STRING_SIZE); - - label_color_parsed = parse_color_argument(label_color, "555"); - value_color_parsed = parse_color_argument(value_color_buffer, "555"); - - wb->content_type = CT_IMAGE_SVG_XML; - - total_width = total_width * scale / 100.0; - height = height * scale / 100.0; - font_size = font_size * scale / 100.0; - text_offset = text_offset * scale / 100.0; - label_width = label_width * scale / 100.0; - value_width = value_width * scale / 100.0; - round_corner = round_corner * scale / 100.0; - - // svg template from: - // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg - buffer_sprintf(wb, - "" - "" - "" - "" - "" - "" - "" - "" - "" - "", - total_width, height, - total_width, height, round_corner, - label_width, height, label_color_parsed); // 0 && fixed_width_val > 0) { - buffer_sprintf(wb, - "" - "" - "", - label_width, height); // ", - label_width, value_width, height, value_color_parsed); - - if(fixed_width_lbl > 0 && fixed_width_val > 0) { - buffer_sprintf(wb, - "" - "" - "", - label_width, value_width, height); - } - - buffer_sprintf(wb, - "" - "" - "" - "%s" - "%s" - "%s" - "%s" - "", - total_width, height, - font_size, - label_width / 2, ceil(height - text_offset), label_escaped, - label_width / 2, ceil(height - text_offset - 1.0), parse_color_argument(text_color_lbl, "fff"), label_escaped, - label_width + value_width / 2 -1, ceil(height - text_offset), value_escaped, - label_width + value_width / 2 -1, ceil(height - text_offset - 1.0), parse_color_argument(text_color_val, "fff"), value_escaped); - - if(fixed_width_lbl <= 0 || fixed_width_val <= 0){ - buffer_sprintf(wb, - "", - BADGE_HORIZONTAL_PADDING); - } - buffer_sprintf(wb, ""); -} - -#define BADGE_URL_ARG_LBL_COLOR "text_color_lbl" -#define BADGE_URL_ARG_VAL_COLOR "text_color_val" - -int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *url) { - int ret = HTTP_RESP_BAD_REQUEST; - buffer_flush(w->response.data); - - BUFFER *dimensions = NULL; - - const char *chart = NULL - , *before_str = NULL - , *after_str = NULL - , *points_str = NULL - , *multiply_str = NULL - , *divide_str = NULL - , *label = NULL - , *units = NULL - , *label_color = NULL - , *value_color = NULL - , *refresh_str = NULL - , *precision_str = NULL - , *scale_str = NULL - , *alarm = NULL - , *fixed_width_lbl_str = NULL - , *fixed_width_val_str = NULL - , *text_color_lbl_str = NULL - , *text_color_val_str = NULL - , *group_options = NULL; - - int group = RRDR_GROUPING_AVERAGE; - uint32_t options = 0x00000000; - - const RRDCALC_ACQUIRED *rca = NULL; - RRDCALC *rc = NULL; - RRDSET *st = NULL; - - while(url) { - char *value = strsep_skip_consecutive_separators(&url, "&"); - if(!value || !*value) continue; - - char *name = strsep_skip_consecutive_separators(&value, "="); - if(!name || !*name) continue; - if(!value || !*value) continue; - - netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value); - - // name and value are now the parameters - // they are not null and not empty - - if(!strcmp(name, "chart")) chart = value; - else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) { - if(!dimensions) - dimensions = buffer_create(100, &netdata_buffers_statistics.buffers_api); - - buffer_strcat(dimensions, "|"); - buffer_strcat(dimensions, value); - } - else if(!strcmp(name, "after")) after_str = value; - else if(!strcmp(name, "before")) before_str = value; - else if(!strcmp(name, "points")) points_str = value; - else if(!strcmp(name, "group_options")) group_options = value; - else if(!strcmp(name, "group")) { - group = time_grouping_parse(value, RRDR_GROUPING_AVERAGE); - } - else if(!strcmp(name, "options")) { - options |= web_client_api_request_v1_data_options(value); - } - else if(!strcmp(name, "label")) label = value; - else if(!strcmp(name, "units")) units = value; - else if(!strcmp(name, "label_color")) label_color = value; - else if(!strcmp(name, "value_color")) value_color = value; - else if(!strcmp(name, "multiply")) multiply_str = value; - else if(!strcmp(name, "divide")) divide_str = value; - else if(!strcmp(name, "refresh")) refresh_str = value; - else if(!strcmp(name, "precision")) precision_str = value; - else if(!strcmp(name, "scale")) scale_str = value; - else if(!strcmp(name, "fixed_width_lbl")) fixed_width_lbl_str = value; - else if(!strcmp(name, "fixed_width_val")) fixed_width_val_str = value; - else if(!strcmp(name, "alarm")) alarm = value; - else if(!strcmp(name, BADGE_URL_ARG_LBL_COLOR)) text_color_lbl_str = value; - else if(!strcmp(name, BADGE_URL_ARG_VAL_COLOR)) text_color_val_str = value; - } - - int fixed_width_lbl = -1; - int fixed_width_val = -1; - - if(fixed_width_lbl_str && *fixed_width_lbl_str - && fixed_width_val_str && *fixed_width_val_str) { - fixed_width_lbl = str2i(fixed_width_lbl_str); - fixed_width_val = str2i(fixed_width_val_str); - } - - if(!chart || !*chart) { - buffer_no_cacheable(w->response.data); - buffer_sprintf(w->response.data, "No chart id is given at the request."); - goto cleanup; - } - - int scale = (scale_str && *scale_str)?str2i(scale_str):100; - - st = rrdset_find(host, chart); - if(!st) st = rrdset_find_byname(host, chart); - if(!st) { - buffer_no_cacheable(w->response.data); - buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1, scale, 0, -1, -1, NULL, NULL); - ret = HTTP_RESP_OK; - goto cleanup; - } - st->last_accessed_time_s = now_realtime_sec(); - - if(alarm) { - rca = rrdcalc_from_rrdset_get(st, alarm); - rc = rrdcalc_acquired_to_rrdcalc(rca); - - if (!rc) { - buffer_no_cacheable(w->response.data); - buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1, scale, 0, -1, -1, NULL, NULL); - ret = HTTP_RESP_OK; - goto cleanup; - } - } - - long long multiply = (multiply_str && *multiply_str )?str2l(multiply_str):1; - long long divide = (divide_str && *divide_str )?str2l(divide_str):1; - long long before = (before_str && *before_str )?str2l(before_str):0; - long long after = (after_str && *after_str )?str2l(after_str):-st->update_every; - int points = (points_str && *points_str )?str2i(points_str):1; - int precision = (precision_str && *precision_str)?str2i(precision_str):-1; - - if(!multiply) multiply = 1; - if(!divide) divide = 1; - - int refresh = 0; - if(refresh_str && *refresh_str) { - if(!strcmp(refresh_str, "auto")) { - if(rc) refresh = rc->update_every; - else if(options & RRDR_OPTION_NOT_ALIGNED) - refresh = st->update_every; - else { - refresh = (int)(before - after); - if(refresh < 0) refresh = -refresh; - } - } - else { - refresh = str2i(refresh_str); - if(refresh < 0) refresh = -refresh; - } - } - - if(!label) { - if(alarm) { - char *s = (char *)alarm; - while(*s) { - if(*s == '_') *s = ' '; - s++; - } - label = alarm; - } - else if(dimensions) { - const char *dim = buffer_tostring(dimensions); - if(*dim == '|') dim++; - label = dim; - } - else - label = rrdset_name(st); - } - if(!units) { - if(alarm) { - if(rc->units) - units = rrdcalc_units(rc); - else - units = ""; - } - else if(options & RRDR_OPTION_PERCENTAGE) - units = "%"; - else - units = rrdset_units(st); - } - - netdata_log_debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'" - , w->id - , chart - , alarm?alarm:"" - , (dimensions)?buffer_tostring(dimensions):"" - , after - , before - , points - , group - , options - ); - - if(rc) { - if (refresh > 0) { - buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh); - w->response.data->date = now_realtime_sec(); - w->response.data->expires = w->response.data->date + refresh; - buffer_cacheable(w->response.data); - } - else - buffer_no_cacheable(w->response.data); - - if(!value_color) { - switch(rc->status) { - case RRDCALC_STATUS_CRITICAL: - value_color = "red"; - break; - - case RRDCALC_STATUS_WARNING: - value_color = "orange"; - break; - - case RRDCALC_STATUS_CLEAR: - value_color = "brightgreen"; - break; - - case RRDCALC_STATUS_UNDEFINED: - value_color = "lightgrey"; - break; - - case RRDCALC_STATUS_UNINITIALIZED: - value_color = "#000"; - break; - - default: - value_color = "grey"; - break; - } - } - - buffer_svg(w->response.data, - label, - (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide, - units, - label_color, - value_color, - precision, - scale, - options, - fixed_width_lbl, - fixed_width_val, - text_color_lbl_str, - text_color_val_str - ); - ret = HTTP_RESP_OK; - } - else { - time_t latest_timestamp = 0; - int value_is_null = 1; - NETDATA_DOUBLE n = NAN; - ret = HTTP_RESP_INTERNAL_SERVER_ERROR; - - // if the collected value is too old, don't calculate its value - if (rrdset_last_entry_s(st) >= (now_realtime_sec() - (st->update_every * gap_when_lost_iterations_above))) - ret = rrdset2value_api_v1(st, w->response.data, &n, - (dimensions) ? buffer_tostring(dimensions) : NULL, - points, after, before, group, group_options, 0, options, - NULL, &latest_timestamp, - NULL, NULL, NULL, - &value_is_null, NULL, 0, 0, - QUERY_SOURCE_API_BADGE, STORAGE_PRIORITY_NORMAL); - - // if the value cannot be calculated, show empty badge - if (ret != HTTP_RESP_OK) { - buffer_no_cacheable(w->response.data); - value_is_null = 1; - n = 0; - ret = HTTP_RESP_OK; - } - else if (refresh > 0) { - buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh); - w->response.data->expires = now_realtime_sec() + refresh; - } - else buffer_no_cacheable(w->response.data); - - // render the badge - buffer_svg(w->response.data, - label, - (value_is_null)?NAN:(n * multiply / divide), - units, - label_color, - value_color, - precision, - scale, - options, - fixed_width_lbl, - fixed_width_val, - text_color_lbl_str, - text_color_val_str - ); - } - -cleanup: - rrdcalc_from_rrdset_release(st, rca); - buffer_free(dimensions); - return ret; -} -- cgit v1.2.3