i'm creating script using nodejs to upload my APK to Google Play Developer via Publishing API, however it failed. I think, it's nothing wrong with APK file, because it's good file. so any idea to solve this ?
i also try multipart upload, but return error ( i will attach here soon )
Below are the Error message :
Upload successful! Server responded with: {
"error": {
"errors": [
{
"domain": "androidpublisher",
"reason": "apkInvalidFile",
"message": "Invalid APK file."
}
],
"code": 403,
"message": "Invalid APK file."
}
}
My Source Code
var https = require('https');
var request = require('request');
https.post = require('https-post');
var fs = require('fs');
var tokens = process.argv[2];
var formData = {
my_file: fs.createReadStream('example_file.apk')
}
if (tokens != '')
{
var url_create_listing = 'https://www.googleapis.com/androidpublisher/v2/applications/com.example.apps/edits?access_token='+tokens;
request.post( url_create_listing, function (error, response, body) {
var str_body = JSON.parse (body);
var listing_id = str_body.id;
var url_upload = 'https://www.googleapis.com/upload/androidpublisher/v2/applications/com.example.apps/edits/'+listing_id+'/apks?uploadType=media&access_token='+tokens;
var options = {
url: url_upload,
headers: {
'Content-Type': 'application/vnd.android.package-archive'
}
};
request.post( options, function optionalCallback(err, httpResponse, body)
{
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
}).pipe(fs.createReadStream('example_file.apk'));
});
}
I think you have a misunderstanding of how NodeJS streams works.
In the sample code you have shown above you are trying to pipe the result of request.post into fs.createReadStream which doesn't make sense and that's reason for the error as you are not sending any apk file. Instead it should be done like the following. (I am not sure how androidpublisher api works, I assume your sample shows the correct usage.)
var url_create_listing = 'https://www.googleapis.com/androidpublisher/v2/applications/com.example.apps/edits?access_token='+tokens;
request.post( url_create_listing, function (error, response, body) {
var str_body = JSON.parse (body);
var listing_id = str_body.id;
var url_upload = 'https://www.googleapis.com/upload/androidpublisher/v2/applications/com.example.apps/edits/'+listing_id+'/apks?uploadType=media&access_token='+tokens;
// request module is capable of auto detecting the Content-Type header
// based on the file extension.
var options = {
url: url_upload
};
fs.createReadStream('example_file.apk')
.pipe(request.post(options, function optionalCallback(err, httpResponse, body){
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
}));
According to https://developers.google.com/games/services/publishing/ :
The Google Play games services Publishing API allows you to automate
frequent tasks having to do (...)
Are you under the absolute constraint to use JS & node.js for this task ? If not, you may find useful this Google management-tools code example.
In this repository you can find tools to help you publish, manage, and
test your Play Games services apps
In my opinion, it is always better to install Python (and re-use official code) to do this.
(Google Devs apparently prefer python for this kind of task)
Have you looked at fastlane.tools? Full scripting of publishing, uploading, taking screenshots, slack notifications, and a lot more for both Android and iOS.
Related
I have a very basic question about a node application, and a question about HTTP requests. It's the first time I create a node app with server, and I just can't seem to get the different components to work together.
This is my server.js
var express = require('express');
var multer = require('multer');
const request = require('request');
const upload = multer({dest: __dirname + '/uploads/images'});
const app = express();
const PORT = 3000;
app.use(express.static('public'));
app.post('/upload', upload.single('photo'), (req, res) => {
if(req.file) {
res.json(req.file);
}
else throw 'error';
});
app.listen(PORT, () => {
console.log('Listening at ' + PORT );
});
Then I have a file app.js with a motion-detection system. Every time motion is detected, a picture is taken. This all works fine.
Then the picture should be sent to the server. This is what I can't figure out.
I created a function toServer() that should post the detected data to the server
const request = require('request');
function toServer(data) {
const formData = {
// Pass data via Buffers
my_buffer: data,
// Pass optional meta-data with an 'options' object with style: {value: DATA, options: OPTIONS}
// Use case: for some types of streams, you'll need to provide "file"-related information manually.
// See the `form-data` README for more information about options: https://github.com/form-data/form-data
};
request.post({url:'http://localhost:3000/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('Upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
};
Problem 1: when running the server.js on localhost:3000, it doesn't find any of the scripts loaded in index.html nor my app.js.
Problem 2: when running the index.html on live-server, all scripts are found, but i get the error "request is not defined".
I am pretty sure there is some basic node setup thing I'm missing.
The solution for toServer() might be more complicated.
Thanks for your time,
Mustard Shaper
Problem 1:
this could happen because you have not specified to render your index.html.
for example:
res.render('index')
if it's not because of the single quotes in upload.single('photo') try double quotes.
Another possible error could be that you are missing a default display engine setting.
an example: https://www.npmjs.com/package/hbs
Problem 2:
it may be because you are missing the header
var request = require('request');
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost',
body: "example"
}, function(error, response, body){
console.log(body);
});
See more at https://expressjs.com/
I have an Express server running.
What i do is upload an Excel File from HTML and then Express parse that file and do some calculating.
In the Excel file, each row has information about address of a User.
For each Address, our Express server will use google map geocoding API to calculate the latitude & longitude.
But, because Google doesn't accept more than 50 request per second to their geocoding API, so i have to use settimeout to delay the calculating.
For example if the Excel file has 50 addresses, so i have to use settimeout on each address to avoid that rate limit.
Here is my code to use settimeout and calculate latitude, longitude
createFromFile(req, res) {
var form = new formidable.IncomingForm();
return form.parse(req, function (err, fields, files) {
if (err)
return res.status(500).json({error: err.message})
var workbook = new exceljs.Workbook();
return workbook.xlsx.readFile(files.excelfile.path).then(function() {
// use workbook
var worksheet = workbook.getWorksheet(1)
var data = []
for (var i=2; i<=worksheet.rowCount; i++) {
data.push({
from_name: worksheet.getCell('A'+i).value + '',
from_address: worksheet.getCell('B'+i).value + '',
from_phone: worksheet.getCell('C'+i).value + '',
receiver_name: worksheet.getCell('D'+i).value + '',
receiver_address: worksheet.getCell('E'+i).value + '',
receiver_phone: worksheet.getCell('F'+i).value + '',
note: worksheet.getCell('H'+i).value + ''
})
}
var delay = function(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t)
})
}
return Promise.all(data.map(function(item, i) {
return function() {
return delay(750*i).then(function() {
winston.log('debug', 'process for item '+i)
return geocoder.geocode(item.from_address).then(function(geo_data) {
data[i].from_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
return geocoder.geocode(item.receiver_address).then(function(geo_data) {
data[i].receiver_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
})
})
.catch(function(geo_error) {
winston.log('error', 'geo_error', {error: geo_error})
throw new Error('Address in line ' + i + ' is not valid')
})
})
}()
}))
.then(function() {
winston.log('debug', 'we are done calculating location')
return res.status(201).json(data)
})
})
.catch(function(e) {
winston.log('error', 'an error occurred')
return res.status(500).json({error: e.message})
})
})
}
And below is my codes to call that Express API, i used React to do frontend job & used javascript fetch api to request to server.
startUploadFile() {
this.props.showLoader()
let data = new FormData()
data.append('excelfile', this.state.selectedFile)
data.append('name', 'excelfile')
var me = this
fetch(Const.restServer + '/create-from-file', {
headers: {
'Access-Token': this.props.access_token,
},
method: 'POST',
body: data
})
.then(function(r) {
return r.json()
})
.then(function(r) {
if (r.hasOwnProperty('error'))
throw new Error(r.error)
me.props.hideLoader()
me.props.showDialog('success', 'Process Complete')
})
.catch(function(e) {
console.log(e)
me.props.hideLoader()
me.props.showDialog('error', e.message)
})
}
My problem is when i used above codes to uploading a file on browser, i see two request in express log file. Something like this:
I will provide my codes to log info of every request here too
app.use(function(req, res, next) {
winston.log('debug', 'call api:', {
api: req.url, requestMethod: req.method
})
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Access-Token, Web-Admin-Request"
);
next()
});
function isAuthenticated(req, res, next) {
/**
** Rest API Middleware check if access_token is valid
*/
let accessToken = req.body.accessToken || req.get('Access-Token')
// bunch of codes to check accessToken
next()
}
app.post('/order/create-from-file', isAuthenticated, orderController.createFromFile);
I don't understand why this happen. If I use Postman & select a File & upload, it works fine - just only One Request in logs.
Can anyone tell me what is the reason. I feel like this is a Bug of Express. My Express version is 4.15.2
The Access-Token request header your code adds to the request triggers browsers to send a CORS preflight OPTIONS request before trying the POST request.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests gives more detail but the gist of it is, as long as your code’s adding that Access-Token header to the request, there’s no way you can prevent browsers from making the extra preflight OPTIONS request—because it’s something browsers do automatically as part of the CORS protocol.
The reason you don’t see the extra request when you use Postman is that it doesn’t do the CORS preflight OPTIONS request—only browsers send it, and only for requests made by XHR/Fetch from frontend JavaScript code running in a browser at a specific origin (which Postman isn’t).
Well, finally i can fix this problem by passing 'Access-Token' into request body instead of request header (now, my server always receive only one request). Thank to #sideshowbarker because your comment trigger me to do this method.
I still think this Problem is a bug in Express, but because it didn't occur on my local development environment, so i will not send a report to them.
I have a weird bug going on with my code.
I'm using the simple-oauth2 library (https://github.com/lelylan/simple-oauth2) and my code works fine on Windows.
When I try to run my code on a linux server (raspberry pi zero), the oauth library keeps on returning 404 Not Found for my oauth request (specifically "Access Token Error Not Found" as per the code below).
What's going on?
Code (working with Yelp API):
var fs = require('fs');
var cID = fs.readFileSync('blahblahblah', 'utf8');
var cSecret = fs.readFileSync('blahblahblah2', 'utf8');
var credentials = {
client: {
id: cID,
secret: cSecret
},
auth: {
tokenHost: 'https://api.yelp.com',
tokenPath: '/oauth2/token'
}
};
var oauth2 = require('simple-oauth2').create(credentials);
var tokenConfig = {};
module.exports.gimmeMuhToken = function(cb) {
oauth2.clientCredentials.getToken(tokenConfig, function(error, result) {
if (error) {
return console.log('Access Token Error', error.message);
}
cb(oauth2.accessToken.create(result).token.access_token); // Return the token
});
};
Thanks
Found the culprit.
It was line endings...
I'm having a sporadic issue with my Node/loopback server. My setup is as follows:
EDIT: My node version is v4.2.4, I'm running Node on Windows 10 Professional.
Client side:
nw.js client that traverses the local file-system and computes the MD5 value of files.
Using a request.post, the client sends the hash of the file to the server in the format 'fileHash: d41d8cd98f00b204e9800998ecf8427e' (that's just an example hash, I know it's an empty file)
function checkHash (fileHash){
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost:3000/api/checkBoths/hashcheck',
method: 'POST',
form: {
fileHash: fileHash
}
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
}
Server side:
Node/loopback server running at localhost:3000.
The hashCheck function is meant to read the data that's posted from the client and query a MySQL database which is for a match of the hash.
The response from the server will be in the format goodResult : true if the hash exists in the database or goodResult : false if not.
var request = require('request');
module.exports = function (CheckBoth) {
var goodResult;
CheckBoth.hashCheck = function (fileHash, cb) {
requestGood(fileHash);
function requestGood (fileHash) {
request.get('http://127.0.0.1:3000/api/Goodhashes/' + fileHash + '/exists', function (error, response, body) {
if (!error && response.statusCode == 200) {
goodResult = JSON.parse(body).exists;
}
if (error) {
console.error(error);
}
});
console.log(goodResult);
}
cb( goodResult);
};
CheckBoth.remoteMethod(
'hashCheck',
{
accepts: {arg: 'fileHash', type: 'string'},
returns: [{arg: 'goodResult', type: 'string'}]
}
);
};
Issue:
The server can respond with ~1000 queries before the following appears throughout the responses:
{ [Error: connect ECONNREFUSED 127.0.0.1:3000]
code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3000 }
I've tried putting in different callbacks within the server code but that has not made any difference. I think I should probably throttle the requests to the server but I don't know how to achieve this.
Any help would be greatly appreciated.
The ulimit default for most systems is 1024. See the manual for limits.conf (http://linux.die.net/man/5/limits.conf).
While #migg is correct about ensuring no memory leaks in your application and its process handling tuning the system for high loads is also normal procedure for quite a few applications.
Try this and see if it helps;
$ ulimit -n 65535
Edit: I have not tested this but here is a document from ibm regarding Windows; http://www-01.ibm.com/support/docview.wss?uid=swg21392080
I'm creating an HTML 5 client to app services, however our app services are enterprise so behind an apigee gateway proxy ( not directly through api.usergrid.com).
I'm initializing like this:
$(function() {
var client = new Apigee.Client({
orgName:'myorg',
appName:'sandbox',
monitoringEnabled:false,
URI:'https://prod.OURURL.com/appservices/v1'
});
var username = "myusername";
var password = "mypass";
client.login(username, password,
function (err) {
if (err) {
console.log('There was an error logging you in.');
} else {
//login succeeded
client.getLoggedInUser(function(err, data, user) {
if(err) {
//error - could not get logged in user
console.log("error on lvl2");
} else {
if (client.isLoggedIn()){
appUser = user;
console.log('data')
// showFullFeed();
}
}
});
}
}
);
});
I'm immediately getting:
Error: Apigee APM configuration unavailable.
and then of course:
There was an error logging you in.
using the trace tool in the proxy I can see this errorr on the request to /proxy_path/org/app/apm/apigeeMobileConfig
{"timestamp":"1398263318219","duration":"0","error":"illegal_argument","exception":"java.lang.IllegalArgumentException","error_description":"JSON source MUST not be null"}
of course this is all called by the above code.
thank you in advance.
[EDIT FOR MORE INFORMATION]
Just tested with my own private org, so not setting the options.URI param, the second log message is normal as I had not created the app user, however the initialization is NOT working on the enterprise org, so this:
var client = new Apigee.Client({
orgName:'myorg',
appName:'sandbox',
monitoringEnabled:false,
URI:'https://prod.OURURL.com/appservices/v1'
});
is returning the APM error.
It seems you need to enable some of the options in the app services app ( inthe configuration option) for this api call to return something, thus enabling the sdk.