appbase
We all dig e-commerce deals: whether’s it’s black friday, holiday special or just a good ol’ product discount offer.
我们都在挖掘电子商务交易:是黑色星期五,节日特惠还是仅仅是一个不错的产品折扣优惠。
In this tutorial, we will use some developer chops to take our love for e-commerce deals to the next level by building a price tracking chrome extension for flipkart.com, India’s largest e-commerce platform. We will break down the codebase and steps in a way that it’s easy for building a similar extension for another e-commerce site like eBay or Amazon.
在本教程中,我们将使用一些开发人员的技巧 ,通过为印度最大的电子商务平台flipkart.com构建价格跟踪功能, 将对电子商务交易的热爱提升到一个新的水平。 我们将分解代码库和步骤,以便轻松地为另一个电子商务网站(例如eBay或Amazon)构建类似的扩展。
Before diving into how to build this, let’s take a look at how it works.
在深入研究如何构建它之前,让我们看一下它是如何工作的。
![Img: A gif showing our chrome extension in action.](https://scotch-res.cloudinary.com/image/upload/w_auto,q_auto:good,f_auto/media/539/8S6MrWZhQteYHC8qdRK6_1-S8V-om35cGhuny-tjJZyWw.gif)
The chrome extension lets you set a price alert when you are browsing product pages of flipkart.com for those specific products. For instance, set a 50% price off alert for the Faridaas tee that’s been on your wishlist since a while. Behind the scenes, the app track prices for the products and sends an e-mail when it matches the alert conditions.
通过chrome扩展程序,您可以在浏览flipkart.com上特定产品的产品页面时设置价格提醒。 例如,为已经存在一段时间的Faridaas T恤设置50%的降价提醒。 在幕后,该应用程序会跟踪产品价格,并在与警报条件匹配时发送电子邮件。
For building this project, we use Javascript (with jQuery) and appbase.io — a hosted #datastreams API for creating realtime queries.
为了构建该项目,我们使用Javascript(带有jQuery)和appbase.io(用于创建实时查询的托管#datastreams API)。
The only pre-requisite for following this tutorial is basic JavaScript chops. And we will cover everything else as we go along. Let’s get started!
遵循本教程的唯一前提条件是基本JavaScript技巧。 我们将继续介绍其他所有内容。 让我们开始吧!
We will break down the project into two components, and look at them one by one:
我们将项目分为两个部分,并一一看待:
- Frontend Javascript and chrome-extension interface, 前端Javascript和chrome-extension界面,
- Backend worker which uses Flipkart APIs and appbase.io for realtime price alerting. 使用Flipkart API和appbase.io进行实时价格警报的后端工作程序。
Chrome扩展程序 ( The Chrome Extension )
Let’s start with the interesting piece. We will be building a chrome extension. A chrome extension. is a static site — a combination of HTML, CSS and JavaScript that allows enhancing the user experience when browsing through Google Chrome.
让我们从有趣的部分开始。 我们将构建一个chrome扩展程序。 chrome扩展名 。 是静态网站-HTML,CSS和JavaScript的组合,可增强在通过Google Chrome浏览器时的用户体验。
Our goal with the chrome extension is to create a price alert UI based on e-commerce product page the user is browsing.
我们使用chrome扩展程序的目标是根据用户正在浏览的电子商务产品页面创建价格提醒用户界面。
步骤1:建立专案 (Step 1: Setup the project)
The first thing we need to do is create the project and add all the files we need for the extension. Let’s start by creating a new directory that we’ll call price-monitoring-frontend. We’ll put all the files we need for the extension in this new folder. Chrome allows us to load up a plugin by pointing it at a folder that contains the extension files.
我们要做的第一件事是创建项目并添加扩展所需的所有文件。 让我们从创建一个新目录开始,我们将其称为price-monitoring-frontend 。 我们会将扩展所需的所有文件都放在这个新文件夹中。 Chrome浏览器允许我们通过将插件指向包含扩展文件的文件夹来加载插件。
price-monitoring-frontend/
|_ _ _ _ js/
| |_ _ _ _ background.js
| |_ _ _ _ index.js
|_ _ _ _ index.html
|_ _ _ _ manifest.json
|_ _ _ _ icon.png
bower install bootstrap
All Chrome extensions require a manifest file. The Manifest file tells Chrome everything it needs to know to properly load up the extension in Chrome. So we’ll create a manifest.json file and put it into the folder we created. You can leave the manifest file blank for now.
所有Chrome扩展程序都需要清单文件。 清单文件告诉Chrome浏览器正确加载Chrome浏览器所需的一切。 因此,我们将创建一个manifest.json文件并将其放入我们创建的文件夹中。 您可以暂时将清单文件留空。
touch manifest.json
Next we’ll need an icon for our extension. This needs to be a 128x128px PNG file and can be named as icon.png. Grab this one if you don’t have one handy.
接下来,我们需要一个扩展图标。 该文件必须为128x128px PNG文件,并可以命名为icon.png。 如果您没有一只方便的物品,请抓住它 。
touch icon.png
Next we’ll need an HTML page to show when a user clicks our Browser Action, so we’ll create index.html file.
接下来,我们需要一个HTML页面来显示用户何时单击我们的浏览器操作,因此我们将创建index.html文件。
touch index.html
Due to security policy of chrome extensions, it is recommended that we avoid any inline JavaScript into HTML files. It’s anyways a good practice to have Javascript and HTML separation. We will create an index.js inside the js directory and will later reference it in the index.html file.
由于chrome扩展程序的安全策略,建议我们避免将任何内联JavaScript插入HTML文件。 无论如何,将Javascript和HTML分开是一个好习惯。 我们将在js目录中创建一个index.js,稍后将在index.html文件中引用它。
mkdir-p js && touch js/index.js
步骤2:创建清单文件 (Step 2: Create the manifest file)
Now that we have a basic project structure in place, we need to add some code to our manifest file to describe our plugin to Chrome.
现在我们已经有了一个基本的项目结构,我们需要在清单文件中添加一些代码来描述我们的Chrome插件。
Usually a good first step in building the chrome extension is figuring out whether it makes more sense as a browser action or a page action. The main difference between the two is in how they appear in the browser’s UI:
通常,构建chrome扩展的一个很好的第一步是弄清楚它是更有意义的浏览器操作还是页面操作 。 两者之间的主要区别在于它们在浏览器UI中的显示方式:
- Browser actions are permanently displayed to the right of the address bar. These are good if your extension can works on multiple websites (think adblock), or if the extension is website agnostic. This is probably the right option for most extensions. 浏览器操作将永久显示在地址栏的右侧。 如果您的扩展程序可以在多个网站上运行(请考虑使用adblock),或者该扩展程序与网站无关,那么这些功能很好。 对于大多数扩展,这可能是正确的选择。
- Page actions are only displayed on certain pages, and their icon appears inside the address bar. This is the right options for extensions that only operate on a single website or specific websites (think Hacker News style enhancer). Page Actions explicitly tell the user which websites they need permissions for. 页面操作仅显示在某些页面上,其图标显示在地址栏中。 对于仅在单个网站或特定网站上运行的扩展程序,这是正确的选择(请考虑使用Hacker News样式增强器)。 页面操作明确告诉用户他们需要访问哪些网站的权限。
Our extension will be a page action, since it only works with one site, flipkart.com.
我们的扩展程序将是页面操作,因为它仅适用于一个网站flipkart.com。
Open the manifest.json file and enter the following code:
打开manifest.json文件并输入以下代码:
{
"manifest_version": 2,
"name": "Flipkart price tracker",
"description": "A flipkart.com extension to track product prices and set email alerts, built with appbase.io.",
"version": "1.0",
"background": {
"scripts": ["js/background.js"],
"persistent": false
},
"page_action": {
"default_icon": "icon.png",
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"*://*/*"
]
}
Most of the fields in this JSON file are self-explanatory, so I won’t waste your time explaining everything, but take note of the browser_action section where we specify what the default icon is and what HTML page should be displayed when the tab url contains flipkart.com.
该JSON文件中的大多数字段都是不言自明的,因此,我不会浪费您的时间来解释所有内容,但请注意browser_action部分,在该部分中,我们指定默认图标是什么,以及在选项卡URL时应显示哪个HTML页面包含flipkart.com。
You’ll also notice I’ve added a permissions section that specifies that we need to have permission to access the activeTab. This is required in order to enable us to get the URL of the current tab to pass on to Extension.
您还将注意到,我添加了一个权限部分,该部分指定我们需要具有访问activeTab的权限。 为了使我们能够获取当前选项卡的URL并将其传递给Extension,这是必需的。
步骤3:建立使用者介面 (Step 3: Create the UI)
The next step is to create the user interface that our Page Action will display when it is clicked.
![](https://i-blog.csdnimg.cn/blog_migrate/37966ea2098d0020ddf8790dcfc5870b.png)
下一步是创建一个用户界面,单击该页面时,我们的Page Action将显示。
Our user interface is going to be very simple that displays the detail about the product and allows to set the range and the email where you want to be notified.
我们的用户界面将非常简单,显示有关产品的详细信息,并允许设置范围和要通知您的电子邮件。
Open up the index.html page and add the following:
打开index.html页面并添加以下内容:
<!doctype html>
<!--
This page is shown when the extension button is clicked, because the
"browser_action" field in manifest.json contains the "default_popup" key with
value "popup.html".
-->
<html>
<head>
<title>Flipkart Price Tracker</title>
<style>
body {
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
min-width: 500px;
}
.form-control {
margin-bottom: 15px;
}
.img-responsive {
margin: 0 auto;
}
</style>
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="js/index.js"></script>
<!--
- JavaScript and HTML must be in separate files: see our Content Security
- Policy documentation[1] for details and explanation.
-
- [1]: https://developer.chrome.com/extensions/contentSecurityPolicy
-->
</head>
<body>
<div class="container">
<!-- Setting the header -->
<div class="row">
<center>
<h3>Flipkart</h3>
<h4>Product Price alert setter</h4>
</center>
</div>
<!-- Form for setting the product price range for getting notification -->
<div class="well">
<select class="form-control inline" id="condition">
<option value="lessThanValue">Less than a Value</option>
<option value="lessThanCurrent">Less than Current Price</option>
<option value="fixedPrice">At a fixed Price</option>
</select>
<input id="greaterThanInput" style="display:none;"></input>
<input class="form-control" id="lessThanInput" placeholder="Set Price"></input>
<input class="form-control" id="email" placeholder="Enter your email"></input>
<center>
<button class="btn btn-primary" id="submit" name="submit">Set Alert</button>
</center>
</div>
<!-- Displaying the product information -->
<table>
<tr>
<td><img id="img" src="" height="200" width="150"></img>
</td>
<td style="padding-left:50px;">
<p><b>Product Name : </b><span id="name"></span></p>
<p><b>Current Price : </b><span id="current_price"></span></p>
</td>
</tr>
</table>
<div class="row">
<img src="images/PoweredBy_Appbase.png" class=img-responsive center-block></img>
</div>
</body>
</html>
You’ll notice in this HTML I’ve included the index.js script. This is where we’ll put the logic for our extension that will execute when the extension is loaded and get notification button is clicked.
您会注意到,在此HTML中,我包括了index.js脚本。 这是我们放置扩展逻辑的地方,它将在加载扩展并单击获取通知按钮时执行。
步骤4:实施逻辑 (Step 4: Implement the logic)
The last thing we need to do to create the plugin is to implement the logic that should execute when a user open the chrome extension icon and clicks the Get Notification button.
创建插件所需做的最后一件事是实现当用户打开chrome扩展程序图标并单击“获取通知”按钮时应执行的逻辑。
First we will edit background.js in js folder, and add the following code:
首先,我们将在js文件夹中编辑background.js,并添加以下代码:
// listen for any changes to the URL of any tab.
chrome.tabs.onUpdated.addListener(function(id, info, tab) {
if (tab.url.toLowerCase().indexOf("flipkart.com") > -1) {
chrome.pageAction.show(tab.id);
}
});
We add the listener on tabs update to check the tab url if it contains the flipkart.com. On success, we display the page action.
我们在标签更新中添加了侦听器,以检查标签网址是否包含flipkart.com。 成功后,我们将显示页面操作。
Now, we will be working on index.js file. We’ll want to add an event listener to listen for the document to be loaded. When user selects the condition for the price range, it updates the variable which we then send it to the server.
现在,我们将处理index.js文件。 我们将要添加一个事件侦听器,以侦听要加载的文档。 当用户选择价格范围的条件时,它会更新变量,然后将其发送到服务器。
When document is ready, we will get the current tab URL by calling getCurrentTabURL(). We check if there is product ID in the url, then we get the product details ( Name, current price ) of the given Product ID and display it in our extension
准备好文档后,我们将通过调用getCurrentTabURL()获得当前的标签URL。 我们检查网址中是否有产品ID,然后获取给定产品ID的产品详细信息(名称,当前价格)并将其显示在扩展名中
When the submit button is clicked, we’ll need to fetch the email and price range at which user wants to be notified. We send the parameters to our server which takes care of notifying when it is matched.
单击提交按钮后,我们将需要获取要通知用户的电子邮件和价格范围。 我们将参数发送到我们的服务器,该服务器负责通知何时匹配。
const serverAddress = "http://104.131.165.92:8081"
var productDetail;
document.addEventListener('DOMContentLoaded', function() {
// When price condition is changed
$('select#condition').on('change', function() {
// If the user has selected "Less than current price"
// We assign greaterThanInput value to 0
// and set the lessThanInput value to current price of the product
if ($('#condition').val() == "lessThanCurrent") {
$('#greaterThanInput').val(0);
$('#lessThanInput').val(productDetail.price);
$('#greaterThanInput').attr('readonly', 'true');
}
// If the user has selected "Fixed price"
// We assign greaterThanInput value to be price entered by user
// and set the lessThanInput value to be price entered by user
else if ($('#condition').val() == "fixedPrice") {
$('#greaterThanInput').val(productDetail.price);
$('#greaterThanInput').val(productDetail.price);
$('#greaterThanInput').removeAttr('readonly');
}
// If the user has selected "Less than a value"
// We assign greaterThanInput value to 0
// and set the lessThanInput value to be price entered by user
else {
$('#greaterThanInput').val(0);
$('#greaterThanInput').removeAttr('readonly');
}
});
// On clicking the set alert button, we make a call to our server
// Sever indexes the product and set a trigger to send mail when condition is met
$('#submit').on('click', function() {
var parameters = {
'lte': $('#lessThanInput').val(),
'gte': $('#greaterThanInput').val(),
'email': $('#email').val(),
'productId': productDetail.productId
}
$.ajax({
type: 'GET',
url: serverAddress + '/alert',
data: parameters,
success: function(d) {
console.log(d);
},
error: function() {
console.log("error");
}
});
alert("You will receive an email, whenever the product price reaches according to you condition.");
});
$(document).ready(function() {
// Get the current tab URL and fetch the product ID
getCurrentTabUrl(function(url) {
if ($.urlParam('pid', url) != null) {
// Fetch the product details from the product ID
getProductDetails({ 'productId': $.urlParam('pid', url) }, function(data) {
// Display the product details in the extension
productDetail = data;
$('#name').text(productDetail.name);
$('#current_price').text(productDetail.price);
var imageURL;
for (var key in productDetail.imageurls) {
imageURL = productDetail.imageurls[key];
}
$('#img').attr('src', imageURL);
});
}
});
});
});
We define getCurrentTabUrl() to get the URL of the active tab.
我们定义getCurrentTabUrl()以获得活动选项卡的URL。
function getCurrentTabUrl(callback) {
// Query filter to be passed to chrome.tabs.query - see
// https://developer.chrome.com/extensions/tabs#method-query
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
// chrome.tabs.query invokes the callback with a list of tabs that match the
// query. When the popup is opened, there is certainly a window and at least
// one tab, so we can safely assume that |tabs| is a non-empty array.
// A window can only have one active tab at a time, so the array consists of
// exactly one tab.
var tab = tabs[0];
// A tab is a plain object that provides information about the tab.
// See https://developer.chrome.com/extensions/tabs#type-Tab
var url = tab.url;
// tab.url is only available if the "activeTab" permission is declared.
// If you want to see the URL of other tabs (e.g. after removing active:true
// from |queryInfo|), then the "tabs" permission is required to see their
// "url" properties.
console.assert(typeof url == 'string', 'tab.url should be a string');
callback(url);
});
}
We then parse the product ID(pid parameter) from the URL fetched.
然后,我们从获取的URL中解析产品ID(pid参数)。
$.urlParam = function(name,url){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(url);
if (results==null){
return null;
}
else{
return results[1] || 0;
}
}
getProductDetails() takes Product ID as parameter and fetches the product details like name and current price from the Flipkart server by making Ajax request.
getProductDetails()以产品ID为参数,并通过发出Ajax请求从Flipkart服务器获取产品详细信息,例如名称和当前价格。
function getProductDetails(parameters, callback) {
$.ajax({
type: 'get',
url: serverAddress + '/product',
data: parameters,
success: function(d) {
callback(d);
},
error: function() {
console.log("error");
}
});
}
构建后端组件 ( Building backend components )
We have frontend of chrome extension in place, where user can interact and set a price to be notified. Now, we will work on the server side aspect which tracks the price changes on Flipkart and notify user when the given condition is met.
![Img: Architecture diagram showing how the system works](https://i-blog.csdnimg.cn/blog_migrate/41ddc8c83fb4be0f69566ebd77490142.png)
我们拥有chrome扩展程序的前端,用户可以在其中进行交互并设置要通知的价格。 现在,我们将在服务器端方面进行工作,该方面跟踪Flipkart的价格变化,并在满足给定条件时通知用户。
步骤1:设定凭证 (Step 1: Setup Credentials)
The first thing we need to do is create the project and all the files we need. Let’s start by creating a new directory that we’ll call “price-monitoring-backend”. We’ll put all the files that we will need to run on server side in this new folder.
我们需要做的第一件事是创建项目和我们需要的所有文件。 让我们从创建一个新目录开始,我们将其称为“ price-monitoring-backend”。 我们将需要在服务器端运行的所有文件放在这个新文件夹中。
price-monitoring-backend/
|_ _ _ _ helper.js
|_ _ _ _ polling.js
|_ _ _ _ index.js
|_ _ _ _ appbase_credentials.json
|_ _ _ _ flipkart_credentials.json
|_ _ _ _ package.json
The above shows how our final directory structure would look. Let’s initialize all these files for later ease of access.
上面显示了最终目录结构的外观。 让我们初始化所有这些文件以便以后访问。
touch helper.js
touch polling.js
touch index.js
touch appbase_credentials.json
touch flipkart_credentials.json
touch package.json
In Node, the package.json file holds the configuration for our app. Node’s package manager (npm) will use this to install any dependencies or modules that we are going to use. We will update package.json with the following json:
在Node中,package.json文件保存了我们应用程序的配置。 Node的程序包管理器(npm)将使用它来安装我们将要使用的所有依赖项或模块。 我们将使用以下json更新package.json:
{
"name": "flipkart_extension",
"version": "1.0.0",
"description": "This is flipkart price alerting extension's backend worker",
"main": "index.js",
"scripts": {
"test": "run"
},
"repository": {
"type": "git",
"url": "https://github.com/appbaseio-apps/price-monitoring-flipkart-backend.git"
},
"homepage": "https://github.com/appbaseio-apps/price-monitoring-flipkart-frontend",
"dependencies": {
"appbase-js": "^0.10.7",
"express": "^4.13.3",
"fs": "0.0.2",
"request": "^2.65.0"
}
}
and then we will install the dependencies by running the following command inside the folder:
然后我们将通过在文件夹中运行以下命令来安装依赖项:
npm install
Next, we will create an app on Appbase and add the app credentials to appbase_credentials.json.
接下来,我们将在Appbase上创建一个应用,并将该应用凭据添加到appbase_credentials.json。
{
"url": "https://scalr.api.appbase.io",
"appname": "your_app_name",
"username": "app_username",
"password": "app_password",
"type": "index_type"
}
We will update the Flipkart API credentials in flipkart_credentials.json
我们将在flipkart_credentials.json中更新Flipkart API凭据
{
"Content-Type": "application/x-www-form-urlencoded",
"Fk-Affiliate-Id":"your_affiliate_id",
"Fk-Affiliate-Token":"your_affiliate_token"
}
If you don’t have flipkart API credential, create an account at Flipkart Affiliate program and get the credentials from their dashboard.
如果您没有flipkart API凭据,请在Flipkart Affiliate程序中创建一个帐户,然后从其仪表板获取凭据。
步骤2:获取Flipkart产品详细信息 (Step 2: Get the Flipkart product details)
We will have to expose the REST APIs that our frontend will interact to set price alert and get product details.
我们必须公开前端将与之交互的REST API,以设置价格警报并获取产品详细信息。
First of all, let the add following code in index.js which will require the necessary packages. You will need to get the sendgrid api key from here and add it below.
首先,让我们在index.js中添加以下代码,这将需要必要的软件包。 您将需要从此处获取sendgrid api密钥,并将其添加到下面。
/*
Requiring necessary helpers.
*/
var express = require('express');
var request = require('request');
var fs = require('fs');
var app = express();
var Appbase = require('appbase-js');
var helper = require("./helper.js");
/*
Including appbase credentials stored in json file.
*/
var appbaseCredentials = require('./appbase_credentials.json');
var sendgrid_api_key = "ENTER_YOUR_SENDGRID_API_KEY_HERE"
/*
Appbase Credentials. Just make new account at appbase and configure it according to your account.
Creating object of appbase, passing appbaseCredentials.
*/
var appbase = new Appbase(appbaseCredentials);
/* This is to access any file withn folder, no routing required for these files. */
app.use('/', express.static(__dirname + '/'));
index.js typically handles your app startup, routing and other functions of your application and does require other modules to add functionality. If you’re running a website or web app it would also handle become a basic HTTP web server replacing the role of something more traditional like Apache.
index.js通常处理应用程序的启动,路由和应用程序的其他功能,并且确实需要其他模块来添加功能。 如果您正在运行网站或Web应用程序,它也将成为基本的HTTP Web服务器,取代了诸如Apache之类的更传统的角色。
Let us write the helper function to get the product details using the Flipkart API and we will expose it globally so that any files can use it. Add the following code in your helper.js file:
让我们编写帮助程序函数,以使用Flipkart API获取产品详细信息,并在全局范围内公开它,以便任何文件都可以使用它。 在您的helper.js文件中添加以下代码:
/*
This is function which just gives details about products and call callback along with the details.
*/
module.exports.getProductDetails = function(productId, callback) {
var request = require('request');
var options = {
uri: 'https://affiliate-api.flipkart.net/affiliate/1.0/product.json?id=' + productId,
method: 'GET',
headers: require('./flipkart_credentials.json')
};
var data;
request(options, function(error, response, body) {
if (!error && response != undefined && response.statusCode == 200) {
data = JSON.parse(body);
console.log(data)
} else {
console.log("Got an error: ", error, ", status code: ", response);
}
}).on('complete', function() {
if (data != undefined)
callback(data);
});
}
Now we will implement the route which takes product id as the parameter and returns product details using the helper function we implemented before:
现在,我们将使用之前实现的辅助函数来实现将产品ID作为参数并返回产品详细信息的路由:
app.get('/product', function(req, res) {
helper.getProductDetails(req.param('productId'), function(data) {
var details = {
'productId': req.param('productId'),
'price': data.productBaseInfoV1.flipkartSpecialPrice.amount,
'name': data.productBaseInfoV1.title,
'imageurls': data.productBaseInfoV1.imageUrls
}
res.send(details);
});
});
步骤3:在满足价格条件时提醒用户 (Step 3: Alert user when the price condition is met)
When a user enters the condition through our chrome extension UI ( i.e press get notification button), we need to store it. We will be creating index_product helper function in helper.js which inserts the product details into the Appbase. It takes two parameter product_id and isUpdated. We use get_product_details function to get the details of the product using product_id and then based on isUpdated flag we insert or update in the Appbase.
当用户通过我们的Chrome扩展程序用户界面输入条件(即,按获取通知按钮)时,我们需要将其存储。 我们将在helper.js中创建index_product helper函数,该函数将产品详细信息插入Appbase。 它带有两个参数product_id和isUpdated。 我们使用get_product_details函数通过product_id获取产品的详细信息,然后根据isUpdated标志在Appbase中插入或更新。
var Appbase = require('appbase-js');
var appbaseCredentials = require('./appbase_credentials.json')
/*
Function for indexing the product detail into appbase.
*/
module.exports.indexProduct = function(productId) {
this.getProductDetails(productId, function(data) {
var price = data.productBaseInfo.productAttributes.sellingPrice.amount;
var name = data.productBaseInfo.productAttributes.productBrand
var appbaseRef = new Appbase(appbaseCredentials);
appbaseRef.index({
type: appbaseCredentials.type,
id: productId,
body: {
'price': price,
'productId': productId,
'name': name
}
}).on('data', function(response) {
console.log(response);
}).on('error', function(error) {
console.log(error);
});
});
}
POST /set_alert takes product_id and range as the input. We will be using searchStreamToURL function of Appbase which will set the webhooks on the condition which is mentioned in the query. It allow us to set an alert without polling for the result at regular interval. We are using sendgrid for sending the mail as soon as condition specified by the user is met.
POST / set_alert将product_id和range作为输入。 我们将使用Appbase的searchStreamToURL函数,该函数将根据查询中提到的条件设置webhooks。 它使我们可以设置警报,而无需定期轮询结果。 一旦满足用户指定的条件,我们将使用sendgrid发送邮件。
app.get('/alert', function(req, res) {
/* Starting polling for the requested product */
var mailBody = "You have set the price alert for flipkart product {{{name}}}. Your condition has been matched and Price has reached to {{{price}}}";
var requestObject = {
type: appbaseCredentials.type,
body: {
"query": {
"filtered": {
"query": {
"match": { "productId": req.param('productId') }
},
"filter": {
"range": {
"price": {
"lt": req.param('lte'),
"gte": req.param('gte')
}
}
}
}
}
}
}
var webhookObject = {
'method': 'POST',
'url': 'https://api.sendgrid.com/api/mail.send.json',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + sendgrid_api_key
},
"count": 1,
'string_body': 'to=' + req.param('email') + '&subject=Your Flipkart product price Alert&text=' + mailBody + '&from=yash@appbase.io'
}
/* Starting stream search for the user condition */
appbase.searchStreamToURL(requestObject, webhookObject).on('data', function(response) {
console.log("Webhook has been configured : ", response);
}).on('error', function(error) {
console.log("searchStreamToURL() failed with: ", error)
})
helper.indexProduct(req.param('productId'));
});
searchStreamToURL() subscribes to search query results on new document inserts and then send the POST request to the endpoint of your choice.
searchStreamToURL()订阅新文档插入中的搜索查询结果,然后将POST请求发送到您选择的端点。
We will write the code for the app to starts a server and listens on port 8081 for connections. The app responds with our routes for requests to the URL be mentioned above. For every other path, it will respond with a 404 Not Found.
我们将为应用程序编写代码以启动服务器,并在端口8081上监听连接。 该应用程序以上面提到的URL响应来响应我们的路由。 对于其他所有路径,它将以404 Not Found响应。
var server = app.listen(process.env.PORT || 8081, '0.0.0.0', function() {
var host = server.address().address;
var port = server.address().port;
console.log('Flipkart extension backend app listening at http://%s:%s', host, port);
});
第4步:轮询Flipkart API以进行价格更改 (Step 4: Poll Flipkart API for price changes)
We will now define polling.js which is responsible for polling Flipkart’s server to fetch current price of all the products in our database.
现在,我们将定义polling.js,它负责轮询Flipkart的服务器以获取数据库中所有产品的当前价格。
We will define start_polling function which takes product_id as the argument and starts the polling for that product. It calls index_product at the interval for 1000 seconds which can be changed. We call index_product with isUpdate flag as true which fetches the product detail and updates in the Appbase with the new value.
我们将定义start_polling函数,该函数将product_id作为参数并开始对该产品的轮询。 它以1000秒的间隔调用index_product,可以更改。 我们将isUpdate标志的isUpdate标志设置为true,以获取产品详细信息并在Appbase中使用新值进行更新。
/*
Requiring necessary helpers.
*/
var Appbase = require('appbase-js');
var helper = require("./helper.js");
/*
Including appbase credentials stored in json file.
*/
var appbase_credentials = require('./appbase_credentials.json');
/*
Appbase Credentials. Just make new account at appbase and configure it according to your account.
Creating object of appbase, passing appbase_credentials.
*/
var appbaseRef = new Appbase(appbase_credentials);
var productList = []
/*
This function is for starting polling of all the productsand storing it into the appbase databse.
The time interval of polling is set to 1000 seconds.
*/
function startPolling() {
function poll() {
setTimeout(function() {
for (productId in productList) {
console.log("Starting polling for the product with Id: " + productList[productId]);
helper.indexProduct(productId);
}
poll();
}, 1000000);
};
poll();
}
We will define fetchProducts function which is our main function responsible for fetching all the products from Appbase for which polling is to be started.
我们将定义fetchProducts函数,这是我们的主要函数,负责从要开始轮询的Appbase中获取所有产品。
At the end, we will make a call to fetchProducts function.
最后,我们将调用fetchProducts函数。
function fetchProducts() {
var requestObject = {
type: appbase_credentials.type,
body: {
query: {
match_all: {}
}
}
};
appbaseRef.search(requestObject).on('data', function(response) {
productList = response.hits.hits.map(function(hit) {
return hit._id;
});
startPolling();
appbaseRef.searchStream(requestObject).on('data', function(stream) {
console.log("Starting polling for new product streamed: " + stream._id);
productList.push(stream._id);
}).on('error', function(error) {
console.log("searchStream() failed with: ", error);
});
}).on('error', function(error) {
console.log("search() failed with: ", error)
});
}
/*
Call to the starter function.
*/
fetchProducts();
Step 5: Running We will run index.js after which our chrome extension can intreact with the server
步骤5:运行我们将运行index.js,之后我们的chrome扩展程序可以与服务器交互
node index.js
We will also run polling.js which will keep the price of the products in our database updated with the current price
我们还将运行polling.js,它将使用当前价格更新数据库中产品的价格
node polling.js
Trying it out It’s really easy to test a new extension in Chrome. Type “chrome://extensions” in a tab to bring up the extensions page.
试试看在Chrome中测试新扩展确实很容易。 在标签中输入“ chrome:// extensions”以打开扩展页面。
![](https://i-blog.csdnimg.cn/blog_migrate/b5c7a220cffc94f294f2a980ca875730.png)
Once on this page, check “Developer mode” to enable loading unpacked extensions. This will allow you to load your extension from a folder. Finally, click “Load unpacked extension” or simply drag the “price-monitoring-frontend” folder onto the page to load up the extension. You should immediately see the extension show up as a Browser Action with your icon in the toolbar window of the current tab.
在此页面上,检查“开发人员模式”以启用加载解压的扩展程序。 这将允许您从文件夹加载扩展名。 最后,单击“加载解压的扩展程序”或简单地将“ price-monitoring-frontend”文件夹拖到页面上以加载扩展程序。 您应该立即看到该扩展名在当前选项卡的工具栏窗口中显示为带有图标的浏览器操作。
To test out the extension, navigate to a product on Flipkart that you want to monitor. Then, go ahead and click the icon for our chrome extension. When the HTML page comes up, set the price range, your email address and “Get Notification” and you will receive email notification when your price range condition is met.
要测试扩展,请在Flipkart上导航到要监视的产品。 然后,继续并点击我们的Chrome扩展程序的图标。 当HTML页面出现时,设置价格范围,您的电子邮件地址和“获取通知”,当您满足价格范围条件时,您将收到电子邮件通知。
![](https://scotch-res.cloudinary.com/image/upload/w_auto,q_auto:good,f_auto/media/539/KVkbqLLXQgSiqHWVDErW_Flipkart.gif)
Here is the link to the repository if you don’t want to copy paste from here and clone directly:
如果您不想从此处复制粘贴并直接克隆,则以下是存储库的链接:
翻译自: https://scotch.io/tutorials/build-a-chrome-extension-for-real-time-price-tracking-with-appbase
appbase