Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ module.exports = {
"always"
],
"no-multi-spaces": [
"error"
"warn"
],
"no-trailing-spaces": [
"error",
"warn",
{
"ignoreComments": true
}
Expand Down
18 changes: 10 additions & 8 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [14, 16, 17]
node: [14, 16, 18, 20, 22, 23]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm install
- run: npm run build --if-present
- run: npm test
Expand All @@ -30,11 +31,12 @@ jobs:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 16.x
node-version: 20.x
cache: 'npm'
- run: npm install
- name: Deploy documentation
shell: bash
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@
**/node_modules
bulk_data/**
**/data
package-lock.json
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 24.10.3
- Added support for uploading user images by providing path to the local image using `picturePath` parameter in `user_details` method (non-bulk)
- Reduced SDK log verbosity

## 24.10.2
- Added timezone support for server

Expand Down
11 changes: 9 additions & 2 deletions examples/bulk_import_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ server.start(function() {
});


var user = server.add_user({device_id: "my_device_id"});
var user = server.add_user({ device_id: "my_device_id_1" });
var user2 = server.add_user({ device_id: "my_device_id_2" });

user.begin_session({_os: "Android", _os_version: "7", _app_version: "1.0"}, 240, 1500645060)
.add_event({key: "Test1", timestamp: 1500645060})
Expand All @@ -44,4 +45,10 @@ user.begin_session({_os: "Android", _os_version: "7", _app_version: "1.0"}, 240,
.custom_min("min", 10)
.custom_push("check", "a")
.custom_push_unique("tags", "morning")
.custom_save();
.custom_save();

user2.begin_session({ _os: "iOS", _os_version: "10", _app_version: "1.0" }, 300, 1500645060)
.add_event({ key: "Test1", timestamp: 1500645060 })
.add_event({ key: "Test2", timestamp: 1500645060 })
.add_event({ key: "Test3", timestamp: 1500645060 })
.user_details({ name: "Test user2", email: "[email protected]" })
20 changes: 11 additions & 9 deletions examples/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ var Countly = require("../lib/countly.js");
Countly.init({
app_key: COUNTLY_APP_KEY,
url: COUNTLY_SERVER_KEY, //your server goes here
debug: true
debug: true,
clear_stored_device_id: true, //just for testing purposes
device_id: "id_" + Math.floor(Math.random() * 1000000) //just for testing purposes
});

Countly.begin_session();
Expand All @@ -27,22 +29,22 @@ setTimeout(function() {
"dur": 1000,
"segmentation": {
"app_version": "1.0",
"country": "Turkey"
"country": "GB"
}
});
}, 5000);

setTimeout(function() {
Countly.user_details({
"name": "Arturs Sosins",
"username": "ar2rsawseen",
"name": "User name",
"username": "User nickname",
"email": "[email protected]",
"organization": "Countly",
"phone": "+37112345678",
//Web URL to picture
"picture": "https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg",
"phone": "+37144345678",
// "picture": "http://www.gravatar.com/avatar/9b8f4f4c3b9b0f2e7f5f4e4e4e4e4e4e",
"picturePath": "./logo.png",
"gender": "M",
"byear": 1987, //birth year
"byear": 1987,
"custom": {
"key1": "value1",
"key2": "value2",
Expand Down Expand Up @@ -73,7 +75,7 @@ setTimeout(function() {
"count": 1,
"segmentation": {
"app_version": "1.0",
"country": "Turkey"
"country": "GB"
}
});
}, 50000);
Expand Down
Binary file added examples/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions lib/countly-bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ CountlyBulk.StorageTypes = cc.storageTypeEnums;
* });
*/
function CountlyBulk(conf) {
var SDK_VERSION = "24.10.2";
var SDK_VERSION = "24.10.3";
var SDK_NAME = "javascript_native_nodejs_bulk";

var empty_queue_callback = null;
Expand Down Expand Up @@ -197,7 +197,7 @@ function CountlyBulk(conf) {
query.hour = query.hour || date.getHours();
query.dow = query.dow || date.getDay();
query.tz = query.tz || -date.getTimezoneOffset();
cc.log(cc.logLevelEnums.INFO, "CountlyBulk add_bulk_request, adding the request into queue.");
cc.log(cc.logLevelEnums.INFO, `CountlyBulk add_bulk_request, adding the request into queue: [${JSON.stringify(query)}]`);
requestQueue.push(query);
}
CountlyStorage.storeSet("cly_req_queue", requestQueue);
Expand Down
2 changes: 1 addition & 1 deletion lib/countly-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ var cc = {
isResponseValidBroad: function isResponseValidBroad(statusCode, str) {
// status code and response format check
if (!(statusCode >= 200 && statusCode < 300)) {
this.log(this.logLevelEnums.ERROR, `isResponseValidBroad, The server status code is not within the expected range: [${statusCode}]`);
this.log(this.logLevelEnums.ERROR, `isResponseValidBroad, The server status code is not within the expected range: [${statusCode}] with: [${str}]`);
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/countly-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const memoryStorage = {
*/
storeSet: function(key, value, callback) {
if (key) {
cc.log(cc.logLevelEnums.DEBUG, `storeSet, Setting key: [${key}] & value: [${value}]!`);
// cc.log(cc.logLevelEnums.VERBOSE, `storeSet, Setting key: [${key}] & value: [${value}]!`);
__cache[key] = value;
if (typeof callback === "function") {
callback(null);
Expand All @@ -74,7 +74,7 @@ const memoryStorage = {
* @returns {varies} value for the key
*/
storeGet: function(key, def) {
cc.log(cc.logLevelEnums.DEBUG, `storeGet, Fetching item from memory with key: [${key}].`);
// cc.log(cc.logLevelEnums.VERBOSE, `storeGet, Fetching item from memory with key: [${key}].`);
return typeof __cache[key] !== "undefined" ? __cache[key] : def;
},
/**
Expand Down
94 changes: 80 additions & 14 deletions lib/countly.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
var os = require("os");
var http = require("http");
var https = require("https");
var fs = require("fs");
var path = require("path");
var cluster = require("cluster");
var cc = require("./countly-common");
var Bulk = require("./countly-bulk");
Expand All @@ -33,7 +35,7 @@ Countly.StorageTypes = cc.storageTypeEnums;
Countly.DeviceIdType = cc.deviceIdTypeEnums;
Countly.Bulk = Bulk;
(function() {
var SDK_VERSION = "24.10.2";
var SDK_VERSION = "24.10.3";
var SDK_NAME = "javascript_native_nodejs";

var inited = false;
Expand Down Expand Up @@ -828,7 +830,8 @@ Countly.Bulk = Bulk;
* @param {string=} user.organization - user's organization or company
* @param {string=} user.phone - user's phone number
* @param {string=} user.picture - url to user's picture
* @param {string=} user.gender - M value for male and F value for femail
* @param {string=} user.picturePath - local path to user's picture, if 'user.picture' is set this will be ignored
* @param {string=} user.gender - M value for male and F value for female
* @param {number=} user.byear - user's birth year used to calculate current age
* @param {Object=} user.custom - object with custom key value properties you want to save with user
* */
Expand All @@ -845,7 +848,12 @@ Countly.Bulk = Bulk;
user.gender = cc.truncateSingleValue(user.gender, Countly.maxValueSize, "user_details", Countly.debug);
user.byear = cc.truncateSingleValue(user.byear, Countly.maxValueSize, "user_details", Countly.debug);
user.custom = cc.truncateObject(user.custom, Countly.maxKeyLength, Countly.maxValueSize, Countly.maxSegmentationValues, "user_details");
toRequestQueue({ user_details: JSON.stringify(cc.getProperties(user, props)) });
var request = { user_details: JSON.stringify(cc.getProperties(user, props)) };
if (!user.picture && user.picturePath) {
cc.log(cc.logLevelEnums.INFO, "user_details, Picture is not set but picturePath is set, will try to upload picture from path.");
request.picturePath = user.picturePath;
}
toRequestQueue(request);
}
};

Expand Down Expand Up @@ -1635,26 +1643,84 @@ Countly.Bulk = Bulk;
isBroad = isBroad || false;
cc.log(cc.logLevelEnums.INFO, `makeRequest, Sending ${info} HTTP request`);
var serverOptions = parseUrl(url);
var data = prepareParams(params);
var data;
var method = "GET";
var options = {
host: serverOptions.host,
port: serverOptions.port,
path: `${api}?${data}`,
path: api,
method: "GET",
};

if (data.length >= 2000 || Countly.force_post) {
method = "POST";
if (params && params.picturePath) {
try {
var filePath = params.picturePath;
var fileName = path.basename(filePath);
var ext = (fileName.split('.').pop() || '').toLowerCase();
var contentType = 'application/octet-stream';
if (ext === 'png') {
contentType = 'image/png';
}
else if (ext === 'jpg' || ext === 'jpeg') {
contentType = 'image/jpeg';
}
else if (ext === 'gif') {
contentType = 'image/gif';
}

var boundary = `FormBoundary${Math.random().toString(16).slice(2)}`;
var bodyParts = [];

for (var p in params) {
if (typeof params[p] !== "undefined" && p !== 'picturePath') {
var value = params[p];
bodyParts.push(Buffer.from(`--${boundary}\r\n`));
bodyParts.push(Buffer.from(`Content-Disposition: form-data; name="${p}"\r\n\r\n`));
bodyParts.push(Buffer.from(String(value)));
bodyParts.push(Buffer.from('\r\n'));
}
}

bodyParts.push(Buffer.from(`--${boundary}\r\n`));
bodyParts.push(Buffer.from(`Content-Disposition: form-data; name="user_picture"; filename="${fileName}"\r\n`));
bodyParts.push(Buffer.from(`Content-Type: ${contentType}\r\n\r\n`));
var fileBuffer = fs.readFileSync(filePath);
bodyParts.push(fileBuffer);
bodyParts.push(Buffer.from('\r\n'));

bodyParts.push(Buffer.from(`--${boundary}--\r\n`));

data = Buffer.concat(bodyParts);
method = "POST";
options.method = "POST";
options.path = api;
options.headers = options.headers || {};
options.headers['Content-Type'] = `multipart/form-data; boundary=${boundary}`;
options.headers['Content-Length'] = data.length;
}
catch (e) {
cc.log(cc.logLevelEnums.ERROR, `makeRequest, Failed preparing picture upload: [${e}]. Falling back to sending request without image.`);
// Remove picturePath to continue with regular request
delete params.picturePath;
}
}

if (method === "POST") {
options.method = "POST";
options.path = api;
options.headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": Buffer.byteLength(data),
};
if (!data) {
data = prepareParams(params);
options.path = `${api}?${data}`;

if (data.length >= 2000 || Countly.force_post) {
method = "POST";
}

if (method === "POST") {
options.method = "POST";
options.path = api;
options.headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": Buffer.byteLength(data),
};
}
}

if (typeof Countly.http_options === "function") {
Expand Down
Loading