blob: d67300b15870f4ced6e152f1a53b9a78383772ff [file] [log] [blame]
susmit6dd649b2015-08-25 14:21:43 -06001/** NDN-Atmos: Cataloging Service for distributed data originally developed
2 * for atmospheric science data
3 * Copyright (C) 2015 Colorado State University
4 *
5 * NDN-Atmos is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * NDN-Atmos is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with NDN-Atmos. If not, see <http://www.gnu.org/licenses/>.
17**/
18
19"use strict";
20var ndn = require("ndn-js");
21var key = require("./key");
22var fs = require("fs");
23
24function RetrieveData(){
25 this.pipelineSize = 4;
26 this.timeoutDict = {};
27 this.retransmissionDict = {};
28 this.existingFileList = [];
29 //FIXME: get this from the config file
30 this.face = new ndn.Face({host: "localhost", port: "6363"});
31
32 this.identityStorage = new ndn.MemoryIdentityStorage();
33 this.privateKeyStorage = new ndn.MemoryPrivateKeyStorage();
34
35 this.keyChain = new ndn.KeyChain(new ndn.IdentityManager(this.identityStorage,
36 this.privateKeyStorage),
37 new ndn.SelfVerifyPolicyManager(this.identityStorage));
38
39 //FIXME:this should be based on the key
40 this.keyName = new ndn.Name("/retrieve/DSK-123");
41 this.certificateName = this.keyName.getSubName(0, this.keyName.size() - 1)
42 .append("KEY").append(this.keyName.get(-1))
43 .append("ID-CERT").append("0");
44
45 this.identityStorage.addKey(this.keyName, ndn.KeyType.RSA,
46 new ndn.Blob(key.DEFAULT_RSA_PUBLIC_KEY_DER, false));
47
48 this.privateKeyStorage.setKeyPairForKeyName(this.keyName,
49 ndn.KeyType.RSA,
50 key.DEFAULT_RSA_PUBLIC_KEY_DER,
51 key.DEFAULT_RSA_PRIVATE_KEY_DER);
52
53 this.face.setCommandSigningInfo(this.keyChain, this.certificateName);
54
55 this.retrievePrefix = new ndn.Name("/retrieve/nwsc");
56 this.face.registerPrefix(this.retrievePrefix, this.onUiInterest.bind(this),
57 this.onRegisterFailed.bind(this));
58 console.log("Registering prefix " + this.retrievePrefix.toUri());
59}
60
61
62RetrieveData.prototype.onUiInterest = function(prefix, interest, face, interestFilterId, filter) {
63 //FIXME: Authenticate Interest
64 var interestName = new ndn.Name(interest.getName());
65 var outgoingInterestName = interestName.getSubName(2).appendSegment(0);
66 console.log("Received Interest" + interest.getName().toUri() +
67 " Requesting " + outgoingInterestName.getName());
68 //send this Interest is from the UI, bind it to a different onData call
69 face.expressInterest(outgoingInterestName, this.onUiData.bind(this), this.onTimeout.bind(this));
70 //using HTTP status codes
71 var retrieveStatus = "200";
72 var statusData = new ndn.Data(interest.getName());
73 statusData.setContent(retrieveStatus);
74 this.keyChain.sign(statusData, this.certificateName);
75 this.face.putData(statusData);
76
77}
78
79RetrieveData.prototype.onUiData = function(Interest, data){
80//this only handles UI data
81 var payload = JSON.parse(data.getContent());
82 console.log("Data is " + payload);
83
84 //go over the loop and ask for each data object in the list
85 for (var entry in payload) {
86 //FIXME: if files exist locally, don't pull them.
87 //FIXME: What if data is more than one packet? Make the UI create packets upto a certain size
88 console.log(payload[entry]); //"aa", bb", "cc"
89 var outgoingInterestName = new ndn.Name(payload[entry]);
90 this.face.expressInterest(outgoingInterestName, this.onData.bind(this),
91 this.onTimeout.bind(this));
92
93
94 }
95 }
96
97
98RetrieveData.prototype.onData = function(interest, data) {
99//this handles normal data
100 var payload = data.getContent();
101 var dataName = new ndn.Name(data.getName());
102 var segment = dataName.get(-1).toSegment();
103 var truncatedName = dataName.getPrefix(-1);
104 var dataFileName = truncatedName.toUri().replace(/\//g, "_");
105 //how do you data is from the UI? Last component is UI
106 var lastComponent = new ndn.Name(truncatedName.getSubName(-1));
107
108 //keep a hashmap of data names and check if data is out of order
109 //if so, drop and rerequest
110
111 //fetch the actual data
112 if (segment === 0){
113 this.retransmissionDict[dataName] = 0;
114 console.log("Logged data segment" + dataName);
115 fs.writeFile(dataFileName, payload, function(err){
116 if(err){
117 return console.log(err);
118 }
119 });
120 }
121 else{
122 fs.appendFile(dataFileName, payload, function(err){
123 if(err){
124 return console.log(err);
125 }
126 });
127 }
128
129 if (data.getMetaInfo().getFinalBlockID() == data.getName()[-1]){
130 fs.close(dataFileName);
131 console.log("Closed file" + dataFileName);
132 }
133 else{
134 //if out of order segment, rerequest
135 if (segment - this.retransmissionDict[dataName] > 1){
136 var reexpressInterest = truncatedName.appendSegment(this.retransmissionDict[dataName] + 1);
137 this.face.expressInterest(reexpressInterest, this.onData.bind(this), this.onTimeout.bind(this));
138 }
139 else{
140 this.retransmissionDict[dataName] = segment;
141 var nextName = truncatedName.appendSegment(segment + this.pipelineSize);
142 this.face.expressInterest(nextName, this.onData.bind(this), this.onTimeout.bind(this));
143 }
144 }
145
146}
147
148RetrieveData.prototype.onTimeout = function(interest) {
149 var dupInterestName = interest.getName().toUri();
150 console.log("Interest timeout for : " + dupInterestName);
151
152 if(!Boolean(this.timeoutDict.hasOwnProperty(dupInterestName))){
153 this.timeoutDict[dupInterestName] = 1;
154 console.log("Logged timeout Interest" + dupInterestName);
155 }
156 if(this.timeoutDict[dupInterestName]!== 3){
157 this.timeoutDict[dupInterestName] = this.timeoutDict[dupInterestName]++;
158 console.log("Retry " + dupInterestName);
159 this.face.expressInterest(interest, this.onData.bind(this), this.onTimeout.bind(this));
160 }
161 else{
162 console.log("No data received for " + dupInterestName + ", giving up");
163 }
164}
165
166RetrieveData.prototype.onRegisterFailed = function(prefix) {
167 console.log("Registration failed for URI: " + prefix.toUri() + " Closing face");
168 this.face.close();
169 }
170
171
172var main = function(){
173 var run = new RetrieveData();
174}
175
176if (require.main === module) {
177 main();
178}