question

lmo avatar image
lmo asked

CDN files upload with nodejs script and https

Hi, I have been trying to upload files by using Nodejs as an alternative to the sdk for untiy which do not work for command line. I did successfully loaded the content from the editor but I need to upload the files from an automatic job for continuous delivery purposes and since the web request do not work by executing untiy in batch mode I need an alternative.

I'm able to authenticate and to get the upload url but when I try to upload a file I always get 501 as an answer.

I have tried different libraries:

https (default included in nodejs)

request.js

postman-request.js

The three of the return 501.

The following code is by using

https

var playfab = require("playfab-sdk");
var request = require("request");
var fs = require("fs");
const url = require('url');
const https = require('https');

function UploadAssets() {
    console.log("Uploading assets started");
    
    playfab.PlayFab.settings.titleId = "xxxx";
    playfab.PlayFab.settings.developerSecretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

    let uploadUrlRequest = {
        "Key": "0.0.0/Andoid/AssetBundlesCollection.json",
        "ContentType": "binary/octet-stream"
    };

    playfab.PlayFabAdmin.GetContentUploadUrl(uploadUrlRequest, (error, result) => {
        if(!error)
        {
            console.log(result.data.URL);
            let resultUri = url.parse(result.data.URL);
            console.log("host = " + resultUri.host);
            console.log("path = " + resultUri.path);
            
            let collection = "D:/Repos/foo/Assets/AssetBundlesCollection.json";


            // https way
            fs.createReadStream(collection).pipe( https.request({
                host: resultUri.host,
                path: resultUri.path,
                method: 'PUT',
                encoding: null,
                headers:{ 
                    'Content-Type' : "binary/octet-stream"
                }
            }, 
            (res) => {
                console.log('STATUS:', res.statusCode);
                console.log('HEADERS:', JSON.stringify(res.headers));
        
                res.setEncoding('utf8');
        
                res.on('data', function (chunk) {
                    console.log('BODY:', chunk);
                });
        
                res.on('end', function () {
                    console.log('No more data in response.');
                })
            }));
        }
    });

    
}

UploadAssets();

I tested by using POSTMAN direclty as described here:

https://api.playfab.com/docs/tutorials/execute-playfab-api-via-postman

I was able to upload the file succesfuly but I'm not able to see any difference between my request with https donde by node.js and the one done by postman, even postman gives node.js code based on the request and it doesn't work, I get the same error.

var playfab = require("playfab-sdk");
var request = require("request");
var fs = require("fs");
const url = require('url');
const https = require('https');
const querystring = require('querystring');

function UploadAssets() {
    console.log("Uploading assets started");
    
    playfab.PlayFab.settings.titleId = "xxxx";
    playfab.PlayFab.settings.developerSecretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

    let uploadUrlRequest = {
        "Key": "0.0.0/Andoid/AssetBundlesCollection.json",
        "ContentType": "binary/octet-stream"
    };

    playfab.PlayFabAdmin.GetContentUploadUrl(uploadUrlRequest, (error, result) => {
        if(!error)
        {
            console.log(result.data.URL);
            let resultUri = url.parse(result.data.URL);
            let query = querystring.parse(resultUri.query);
            console.log("protocol = " + resultUri.protocol + "\n");
            console.log("\nhost = " + resultUri.host + "\n");
            console.log("pathname = " + resultUri.pathname + "\n");
            console.log("path = " + resultUri.path + "\n");
            console.log("qs = " + resultUri.query + "\n");
            
            let collection = "D:/Repos/foo/Assets/AssetBundlesCollection.json";

           // postman https suggestion
           var options = { method: 'PUT',
            url: resultUri.protocol + "//" + resultUri.host + resultUri.pathname,
            qs: query,
            headers: { 'content-type': 'binary/octet-stream' } };

            console.log(JSON.stringify(options, null, 2));

            fs.createReadStream(collection).pipe(request(options, function (error, response, body) {
                if (error) throw new Error(error);
                console.log(body);
            }));
        }
    });

    
}

UploadAssets();
apissdksContent
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

lmo avatar image
lmo answered

I found the solution, I found out with postman desktop application that the content-length, accept and cache-control headers where being sent, with them it works perfect. For some strange reason the postman chrome extension do not show those headers.

let UploadFile = (filepath, remotepath) =>
{
    console.log("Uploading " + filepath + " to " + remotepath);
    let uploadUrlRequest = {
        "Key": remotepath,
        "ContentType": "binary/octet-stream"
    };

    playfab.PlayFabAdmin.GetContentUploadUrl(uploadUrlRequest, (error, result) => {
        if(!error)
        {
            let resultUri = url.parse(result.data.URL);
            let query = querystring.parse(resultUri.query);
            
            let binarybuf = fs.readFileSync(filepath, null);

            var options = { method: 'PUT',
                    url: resultUri.protocol + "//" + resultUri.host + resultUri.pathname,
                    qs: query,
                    body: binarybuf,
                    encoding: null,
                    headers: { 
                        'content-type': 'binary/octet-stream',
                        'cache-control': 'no-cache',
                        'accept' : '*/*',
                        'content-length' : binarybuf.byteLength
                    }
            };

            request(options, function (error, response, body) {
                if (error) throw new Error(error);
                console.log(  resultUri.pathname + " / " + response.statusCode + " / " +response.statusMessage);
            });
        }
    });
}

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Andy avatar image
Andy answered

One caveat, I've never tried to do this from node.js. That being said, I'm a little curious about the url parameter in your options object. Based on the latest node.js api docs, it doesn't look like that's a valid option. It does look like https.request will also accept a URL object directly, but it shouldn't be wrapped inside of an options object.

Hopefully that's helpful. Good Luck!

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.