Welcome to the tutorial of creating a project by yourself. Let's start!
Note: All the functions are asynchronous and return promises.
First and foremost you need to have all the keys and configuration to connect to the storj network. You can create a JSON file and parse the JSON file to sotre the values in a class/strucure or you can simply initialize the corrsponding variables inside the main method as done in the sample HelloStorj.js file in the following way:
var storjConfig = {
apiKey : "change-me-to-the-api-key-created-in-satellite-gui",
satelliteURL : "us-central-1.tardigrade.io:7777",
encryptionPassphrase : "you'll never guess this",
bucketName : "change-me-to-desired-bucket-name",
uploadPath : "optionalpath/requiredfilename",
};
File path could be path of the file to be upload from or path where a file needs to be download at or both. You can create a JSON file and parse it or simply initialize file path variable(s) as done in the sample HelloStorj.js file in the following way:
var localFullFileName = {
src : "change-me-to-source-file-name-at-local-system",
dest: "change-me-to-destination-file-name-at-local-system",
};
Next, you need to create an object of Uplink class that will be used to call the libuplink functions.
const storj = require("uplink-nodejs");
const libUplink = new storj.Uplink();
Now we need to get access handle to Storj V3 network. For that we can use any of these functions:
//first method for handling promise
libUplink.requestAccessWithPassphrase(satelliteURL,apiKey,encryptionPassphrase).then(access => {
....//some code//....
}).catch((err) => {
....//some code//....
});
//or
//second method for handling promise
var access = await libUplink.requestAccessWithPassphrase(satelliteURL,apiKey,encryptionPassphrase).catch((err) => {
....//some code//....
});
....//some code//....
The function accepts 3 arguments Satellite URL, API Key, and Passphrase and returns an AccessResult object (access) on successful execution which can be used to call other functions which are bound to it.
NOTE: We will be use first convention for handling promise in our documentation but user are free to use second convention.
libUplink.configRequestAccessWithPassphrase(satelliteURL,apiKey,encryptionPassphrase).then(access => {
....//some code//....
}).catch((err) => {
....//some code//....
});
The function accepts 4 arguments Config Object, Satellite URL, API Key, and Passphrase and returns an AccessResult object (access) on successful execution which can be used to call other functions which are bound to it.
libUplink.parseAccess(stringResult).then(async (parsedSharedAccess) => {
....//some code//....
}).catch((err) => {
....//some code//....
});
The function accepts a Serialized Access (String) and returns an AccessResult object (parsedSharedAccess) on successful execution which can be used to call other functions which are bound to it.
NOTE: parse_access can be called only after getting a Serialized Access String which is given by function access_serialize.
Once we have the Access handle, it can be used to open a project using any of these functions:
access.openProject().then(async (project) => {
...//some code//...
}).catch((err) => {
....//some code//....
});
This function is a property of accessResult which is returned by Access Functions and denoted as 'access' in the above codes. It returns project on successful execution.
access.configOpenProject(config).then(async (project) => {
...//some code//...
}).catch((err) => {
....//some code//....
});
This function is a property of 'access' which is returned by Access Functions. It accepts a config object and returns project on successful execution. The project used in the steps ahead refers to this project object only.
After getting project we need a bucket for further execution. If a bucket is not available, one is created otherwise information about current bucket is collected and execution moves ahead. We use stat_bucket function to get information about the bucket.
await project.statBucket(bucketName).then((bucketInfo) => {
...//some code//...
}).catch((err) => {
....//some code//....
});
This function accepts one arguments, a bucketname and returns bucketInfo (information about the current bucket)
NOTE: If the specified bucket does not exist, it is created using the function below
await project.createBucket(bucketName).then((bucketInfo) => {
...//some code//...
}).catch((err) => {
....//some code//....
});
This function accepts one arguments, a bucketname, creates the bucket and returns bucketInfo (information about the current bucket)
After creating the bucket, it is important to ensure that the bucket exists on Storj V3 network before moving ahead.
await project.ensureBucket(bucketName).then((bucketInfo) => {
...//some code//...
}).catch((err) => {
....//some code//....
});
This function accepts one arguments, a bucketname, ensures that the bucket is present on Storj V3 network and returns bucketInfo (information about the current bucket)
Once it is ensured that bucket exists on Storj V3 network, you can list all the buckets. However this step is completely optional. If you don't wish to list the buckets, you can skip this step.
var listBucketsOptions = new storj.ListBucketsOptions();
await project.listBuckets(listBucketsOptions).then(async (bucketListResult) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
This function accepts one arguments, listBucketOptions and returns bucketListResult.
Uploading a file consists of following sub-steps:
var uploadOptions = new storj.UploadOptions();
uploadOptions.expires = 0;
await project.uploadObject(bucketName,uploadPath,uploadOptions).then(async (upload) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
This function accepts 3 arguments bucketname, uploadpath and uploadoptions. It then returns an uploadinfo object.
You can create uploadOptions by referring to the libuplink documentation or simply pass none.
To stream the data to storj you need to create a file stream or handle which can be done in the following way. Here uploadinfo is your upload handle.
await project.uploadObject(bucketName,uploadPath,uploadOptions).then(async (upload) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
Now we need to create buffer to store our file's data. It can be done in the following way.
var size = {
file : `${await fs.statSync(localFullFileName.src).size}`,
toWrite : 0,
actuallyWritten : 0,
totalWritten : 0
};
//
var buffer = new Buffer.alloc(BUFFER_SIZE);
var loop = true;
var bytesRead = 0;
while (loop) {
//
size.toWrite = size.file - size.totalWritten;
//
if (size.toWrite > BUFFER_SIZE) {
size.toWrite = BUFFER_SIZE;
} else if (size.toWrite === 0) {
break;
}
//
bytesRead = await fs.readSync(fileHandle, buffer, 0, size.toWrite, size.totalWritten);
Once we have the File Handle and Buffer, we can upload data to Storj V3 network in the following way:
await upload.write(buffer,bytesRead).then((writeResult) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
Once the data has been successfully streamed, the upload needs to be committed using the following method:
await upload.commit().then(() => {
...//some_code//...
}).catch((err) => {
...//some_code//...
});
Downloading a file consists of following steps:
We need to create a download handle first in the following way. In the code, downloadresult is your
var downloadOptions = new storj.DownloadOptions();
downloadOptions.offset = 0;
downloadOptions.length = -1;
await project.downloadObject(bucketName,uploadPath,downloadOptions).then(async (download) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
After creating the download handle, we need to get info about the object to be downloaded by using the following function:
await download.info().then((objectInfo) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
Now we need to create a download buffer and file handle in the same way as we did for upload.
var size = { download : 0,
actuallyWritten : 0,
totalWritten : 0};
var buffer = new Buffer.alloc(BUFFER_SIZE);
var fileHandle = await fs.openSync(localFullFileName.dest, "w");
var loop = true;
while(loop) {
if((objectsize-size.totalWritten>0)&&(objectsize-size.totalWritten)<BUFFER_SIZE){
buffer = null;
buffer = new Buffer.alloc(objectsize-size.totalWritten);
}
Now we can download the object from Stroj V3 server using the following function.
await download.read(buffer,buffer.length).then(async (bytesread) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
When the file is downloaded, you need to close the downlaod stream. It can be done in the following way:
fs.closeSync(fileHandle);
await download.close().then(() => {
...//some_codee//...
}).catch((err) => {
....//some code//....
});
NOTE: Perform error handling as as per your implmentation.
NOTE: Alternatively, you can simple create a method(s) that can be called from the main method and performs all the above steps internally as done in the sample file.
To provide shared access, we can use this function
// set permissions for the new access to be created
var permission = new storj.Permission(true,true,true,true,0,0);
// set shared prefix
var sharePrefix = storj.SharePrefix;
var sharePrefixListArray = [];
sharePrefix.bucket = "change-me-to-desired-bucket-name";
sharePrefix.prefix ="change-me-to-desired-object-prefix";
sharePrefixListArray.push(sharePrefix);
// create new access
await access.share(permission,sharePrefixListArray,sharePrefixListArray.length).then(async (sharedAccess) => {
// generate serialized access to share
await sharedAccess.serialize().then(async (stringResult) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
}).catch((err) => {
....//some code//....
});
To delete an object, we can use the following function:
await project.deleteObject(bucketName,uploadPath).then((objectinfo) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
This function accepts 2 arguments, bucketname and uploadpath to identify the object to be deleted and returns information about the deleted object.
To delete a bucket, we can use the following function:
await project.deleteBucket(bucketName).then((bucketInfo) => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
After finalizing everything, you can close the project in following way;
await project.close().then(() => {
...//some_code//...
}).catch((err) => {
....//some code//....
});
NOTE: For more binding functions refer to the uplink-nodejs Binding Functions and for implemtation purpose refer HelloStorj.js file.