Skip to content

Commit 4dda4da

Browse files
committed
Upload profile pics of servers
1 parent b4ca0dc commit 4dda4da

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

api/parts/mgmt/tracker.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ var tracker = {},
88
stats = require('../data/stats.js'),
99
common = require('../../utils/common.js'),
1010
logger = require('../../utils/log.js'),
11+
countlyFs = require('../../utils/countlyFs.js'),
1112
//log = logger("tracker:server"),
1213
Countly = require('countly-sdk-nodejs'),
1314
fs = require('fs'),
1415
path = require('path'),
16+
https = require('https'),
17+
http = require('http'),
18+
FormData = require('form-data'),
19+
{ Readable } = require('node:stream'),
1520
versionInfo = require('../../../frontend/express/version.info'),
1621
server = "9c28c347849f2c03caf1b091ec7be8def435e85e",
1722
user = "fa6e9ae7b410cb6d756e8088c5f3936bf1fab5f3",
@@ -72,6 +77,17 @@ tracker.enable = function() {
7277

7378
isEnabled = true;
7479
Countly.user_details({"name": config.device_id });
80+
if (plugins.getConfig("white-labeling") && (plugins.getConfig("white-labeling").favicon || plugins.getConfig("white-labeling").stopleftlogo || plugins.getConfig("white-labeling").prelogo)) {
81+
var id = plugins.getConfig("white-labeling").favicon || plugins.getConfig("white-labeling").stopleftlogo || plugins.getConfig("white-labeling").prelogo;
82+
countlyFs.gridfs.getDataById("white-labeling", id, function(errWhitelabel, data) {
83+
if (!errWhitelabel && data) {
84+
tracker.uploadBase64FileFromGridFS(data).catch(() => {});
85+
}
86+
});
87+
}
88+
else {
89+
Countly.user_details({"picture": "./images/favicon.png" });
90+
}
7591
if (plugins.getConfig("tracking").server_sessions) {
7692
Countly.begin_session(true);
7793
}
@@ -420,6 +436,114 @@ tracker.getSDKData = async function() {
420436
}
421437
};
422438

439+
/**
440+
* Upload a base64-encoded file from GridFS to the stats server
441+
* This function handles files stored in GridFS as base64 strings (e.g., data URIs)
442+
* and decodes them before uploading
443+
*
444+
* @param {Object} base64String - Picture data
445+
* @returns {Promise<Object>} Upload result
446+
*/
447+
tracker.uploadBase64FileFromGridFS = function(base64String) {
448+
return new Promise((resolve, reject) => {
449+
var domain = stripTrailingSlash((plugins.getConfig("api").domain + "").split("://").pop());
450+
if (domain && domain !== "localhost") {
451+
try {
452+
let mimeType = "image/png";
453+
// Strip data URI prefix if present and stripDataURI is true
454+
if (base64String.includes('base64,')) {
455+
// Extract MIME type from data URI if not provided
456+
const dataURIMatch = base64String.match(/^data:([^;]+);base64,/);
457+
if (dataURIMatch) {
458+
mimeType = dataURIMatch[1];
459+
}
460+
// Remove data URI prefix
461+
base64String = base64String.split('base64,')[1];
462+
}
463+
464+
// Decode base64 to binary buffer
465+
const binaryBuffer = Buffer.from(base64String, 'base64');
466+
467+
// Create a readable stream from the decoded buffer
468+
const decodedStream = Readable.from(binaryBuffer);
469+
470+
// Parse the URL
471+
const statsUrl = new URL(url);
472+
const protocol = statsUrl.protocol === 'https:' ? https : http;
473+
474+
// Build query parameters
475+
const queryParams = new URLSearchParams({
476+
device_id: domain,
477+
app_key: server,
478+
user_details: ""
479+
});
480+
481+
// Create form data
482+
const form = new FormData();
483+
484+
// Prepare form options with MIME type if available
485+
const formOptions = { filename: "profile" };
486+
if (mimeType) {
487+
formOptions.contentType = mimeType;
488+
}
489+
490+
form.append('file', decodedStream, formOptions);
491+
492+
// Prepare request options
493+
const requestOptions = {
494+
hostname: statsUrl.hostname,
495+
port: statsUrl.port || (statsUrl.protocol === 'https:' ? 443 : 80),
496+
path: `/i?${queryParams.toString()}`,
497+
method: 'POST',
498+
headers: form.getHeaders()
499+
};
500+
501+
// Make the request
502+
const req = protocol.request(requestOptions, (res) => {
503+
let data = '';
504+
505+
res.on('data', (chunk) => {
506+
data += chunk;
507+
});
508+
509+
res.on('end', () => {
510+
if (res.statusCode >= 200 && res.statusCode < 300) {
511+
try {
512+
const result = JSON.parse(data);
513+
resolve({
514+
success: true,
515+
statusCode: res.statusCode,
516+
data: result
517+
});
518+
}
519+
catch (e) {
520+
resolve({
521+
success: true,
522+
statusCode: res.statusCode,
523+
data: data
524+
});
525+
}
526+
}
527+
else {
528+
reject(new Error(`Upload failed with status ${res.statusCode}: ${data}`));
529+
}
530+
});
531+
});
532+
533+
req.on('error', (error) => {
534+
reject(error);
535+
});
536+
537+
// Pipe the form data to the request
538+
form.pipe(req);
539+
}
540+
catch (error) {
541+
reject(error);
542+
}
543+
}
544+
});
545+
};
546+
423547
/**
424548
* Check if running in Docker environment
425549
* @returns {boolean} if running in docker

0 commit comments

Comments
 (0)