在 Node.js 中使用 PhoneGap Build API 包

openkk 12年前發布 | 36K 次閱讀 Node.js JavaScript開發

昨天我在Node中使用了PhoneGap Build API包。我將它上傳到了: https://github.com/germallon/phonegapbuildapi,我認為這是一個很有趣的試驗。 Build API是真的簡單,所以我認為我的代碼也將是非常簡單的。

首先,我開始閱讀它的API部分。它可以獲取到應用程序,圖標,下載的東西,等等。PhoneGap允許每次請求一個令牌或通過身份驗證信息。于是,我通過簡單地方式驗證每個請求,并且讓大部分的API邏輯都調用兩個通用函數:

function getConfig(path) {
    return {
        auth: username + ":" + password,
        host:"build.phonegap.com",
        port:"443",
        path:"/api/v1/"+path
    }
}

//I handle doing the config get, http, string contact, etc function doCall(path, success, fail) { var options = getConfig(path); var req = http.get(options, function(res) { var resultString = ""; res.on("data", function(c) { resultString+=c; });

    res.on("end",function() {
        var result = JSON.parse(resultString);
        success(result);
    });
}).on("error", function(e) {
    if(fail) fail(e);
});

}</pre>
這里doCall是核心函數,它解析API的路徑。所有的API都調用相同的基URL,所以我讓它更加簡單,只需要加上path。Node中調用HTTP比CF要復雜一些,因為它們是異步的,但也并不困難。你可能會猜想這段代碼里發生了什么。我打開一個請求,它會獲得到一個結果對象。結果對象有一個數據事件。我將數據追加到一個結果變量。這里還有一個結束事件,在結束事件中我們可以用json解析結果變量,并發送成功的處理。

以下是一個獲得所有應用程序的例子:

exports.getAllApps = function(success,fail) {
    doCall("apps", function(res) {
        if(res.error && res.error.length && fail) fail(res.error);
        else success(res.apps);
    },function(e) {
        if(fail) fail(e);
    });

最后,讓Node應用程序使用它:

pgbuild = require("./pgbuild");

pgbuild.setUsername("ray@camdenfamily.com"); pgbuild.setPassword("isitmillertimeyet?");

//Test getting all the apps pgbuild.getAllApps(function(apps) { console.log("I got lots of apps! How many? "+apps.length); //console.dir(apps); }, function(e) { console.log("Oh snap, an error"); console.dir(e); });</pre>
我寫的大部分代碼都遵循API的這種格式 - 通過一個成功/失敗的來處理程序。

所以我說這些都是非常簡單的。我想我大概用了30分鐘左右閱讀API。然后我開始編寫API時碰壁了。為什么?我想創建一個應用程序,允許你上傳的文件并定義新應用程序。你也可以將新應用程序指定在一個存儲庫,但我想先做好文件版本。(打電話給我一個貪吃的朋友)證明上傳文件在后面更加痛苦。沒有真正內置的支持核心的Node.js庫。谷歌搜索真的很困難,因為幾乎所有的結果是關于如何處理文件上傳,而不是文件上傳請求。

經過我一番瘋狂搜索,我發現這篇 文章。我在想這人的真正名字,但他(她)的關于頁面實際上并沒有說他(她)是誰。因此我決定這個人是……

在 Node.js 中使用 PhoneGap Build API 包

……根據他(她)說的。我將他的一些邏輯寫進了我最終的代碼,雖然我對這種混合不是很滿意,但是它確實很管用。下面是一個調用示例:

pgbuild.createApp({
    title:"New App for Testing",
    create_method:"file",
    file:"./forupload/index.html"
    }, function(res) {
        console.log("Ok in making an app");
        console.dir(res);
    }, function(e) {
        console.log("I got an error: ");
        console.dir(e);
    }
);

這是一個用PhoneGap新構建的網站。

在 Node.js 中使用 PhoneGap Build API 包

有趣的是,瀏覽器使JavaScript上傳文件比XHR2更加容易。如果你還沒有看到這一動作,請查看優秀的 HTML5 Rocks這篇文章。

下面我將整個pgbuild.js代碼貼出來:

 

var http = require("https");
var fs = require("fs");
var path = require("path");

var username = ""; var password = "";

exports.setUsername = function(u) { username = u; } exports.setPassword = function(p) { password = p; }

exports.createApp = function(options, success, fail) { var httpOptions = getConfig("apps"); httpOptions.method = "POST";

//Detect if options.create_method is file, and if so, suck in the bits
//Fails if no .file
//Also note it doesn't support .zip yet.
if(options.create_method === "file") {
    if(!options.file) throw new Error("Must supply file value.");
    console.log("Need to read in a file:"+options.file);
    //Shell out for file uploads
    PreparePost(httpOptions,JSON.stringify(options), options.file, success);
} else {
    //TODO
}

}

exports.getAllApps = function(success,fail) { doCall("apps", function(res) { if(res.error && res.error.length && fail) fail(res.error); else success(res.apps); },function(e) { if(fail) fail(e); }); }

exports.getApp = function(id, success, fail) { doCall("apps/"+id, function(res) { if(res.error && res.error.length && fail) fail(res.error); else success(res); },function(e) { if(fail) fail(e); }); }

exports.getAppIcon = function(id, success, fail) { doCall("apps/"+id +"/icon", function(res) { if(res.error && res.error.length && fail) fail(res.error); else success(res.location); },function(e) { if(fail) fail(e); }); }

//todo: Possibly validate platform? Should be: android,blackberry,ios,symbian,webos,winphone exports.getAppDownload = function(id, platform, success, fail) { doCall("apps/"+id +"/"+platform, function(res) { if(res.error && res.error.length && fail) fail(res.error); else success(res.location); },function(e) { if(fail) fail(e); }); }

exports.getKeys = function() { var platform = ""; if(arguments.length == 1) { success = arguments[0]; } else if(arguments.length === 2) { success = arguments[0]; fail = arguments[1]; } else if(arguments.length == 3) { platform = arguments[0]; success = arguments[1]; fail = arguments[2]; }

var path = "keys";
if(platform != "") path+="/"+platform;

doCall(path, function(res) {
    if(res.error && res.error.length && fail) fail(res.error);
    else success(res.keys);
},function(e) {
    if(fail) fail(e);
});

}

exports.getKey = function(platform, id, success, fail) { doCall("keys/"+platform +"/"+id, function(res) { if(res.error && res.error.length && fail) fail(res.error); else success(res); },function(e) { if(fail) fail(e); }); }

function getConfig(path) { return { auth: username + ":" + password, host:"build.phonegap.com", port:"443", path:"/api/v1/"+path } }

//I handle doing the config get, http, string contact, etc function doCall(path, success, fail) { var options = getConfig(path); var req = http.get(options, function(res) { var resultString = ""; res.on("data", function(c) { resultString+=c; });

    res.on("end",function() {
        var result = JSON.parse(resultString);
        success(result);
    });
}).on("error", function(e) {
    if(fail) fail(e);
});

}

//CREDIT: http://onteria.wordpress.com/2011/05/30/multipartform-data-uploads-using-node-js-and-http-request/ //Note that I modified his code quite a bit

//For file uploads function EncodeFieldPart(boundary,name,value) { var return_part = "--" + boundary + "\r\n"; return_part += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n"; return_part += value + "\r\n"; return return_part; }

function EncodeFilePart(boundary,type,name,filename) { var return_part = "--" + boundary + "\r\n"; return_part += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"; return_part += "Content-Type: " + type + "\r\n\r\n"; return return_part; }

//I expect the config options, the JSON data string, and file path function PreparePost(httpOptions,data,file,success) { var boundary = Math.random(); var post_data = [];

post_data.push(new Buffer(EncodeFieldPart(boundary, 'data', data), 'ascii'));
post_data.push(new Buffer(EncodeFilePart(boundary, 'text/plain', 'file', path.basename(file)), 'ascii'));

var contents = fs.readFileSync(file, "ascii");
post_data.push(new Buffer(contents, "utf8"));
post_data.push(new Buffer("\r\n--" + boundary + "--"), 'ascii');

MakePost(httpOptions,post_data, boundary,success);

}

function MakePost(httpOptions,post_data, boundary,success) {

var length = 0;

for(var i = 0; i < post_data.length; i++) {
    length += post_data[i].length;
}

httpOptions.headers = {
    'Content-Type' : 'multipart/form-data; boundary=' + boundary,
    'Content-Length' : length
};

var post_request = http.request(httpOptions, function(response){
    response.setEncoding('utf8');
    var res="";
    response.on('data', function(chunk){
        res+=chunk;
    });
    response.on('end',function() {
        success(JSON.parse(res));
    });
});

for (var i = 0; i < post_data.length; i++) {
    post_request.write(post_data[i]);
}
post_request.end();

}</pre>

 

原文地址

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!