CoSync AssetLink

CoSync AssetLink #

Overview #

The purpose of CoSync AssetLink is to streamline the integration of asset data, such as images, videos, and large files, into applications constructed atop MongoDB App Services using the Realm database. While MongoDB Realm is widely recognized as a leading real-time collaborative database, it lacks native support for handling image and video data that requires streaming.

At its core, MongoDB Realm functions as an object database, primarily storing JSON data, which includes various data types like numbers, strings, arrays, and containers. However, many collaborative client applications frequently encounter the need to manage substantial assets, such as images and videos. This requirement is particularly common, with user profiles often including elements like avatars.

Currently, the predominant method for storing images in a MongoDB Realm application entails the utilization of Base64 encoding. This technique, originating in the early 1990s, involves the conversion of binary image data into ASCII text. While it was initially employed for posting images on Internet forums, it presents certain challenges when integrated into modern applications.

The primary drawback of this approach lies in its two-way conversion process, which is necessary for storing and displaying images within an application. Additionally, it leads to a substantial increase in the size of synchronized object data within Realm. This expansion not only escalates storage costs but also results in higher network expenses.

For video data, employing Base64 encoding becomes impractical, requiring the segmentation of Base64 video data into multiple chunks that must later be reassembled at the client device’s edge. This approach severely impedes video streaming from a Content Delivery Network (CDN). Similar constraints apply to audio data and the management of large files.

From an application perspective, the optimal solution involves storing images and videos on a CDN, accompanied by secure HTTPS URLs. Furthermore, for image data, it is imperative to maintain cuts at various resolutions to cater to the diverse requirements of client devices. This approach enhances both efficiency and performance within the application.

For application developers working with MongoDB Realm, accommodating these assets typically entails establishing additional infrastructure to facilitate image uploads to a Content Delivery Network (CDN) and recording their corresponding URLs within a MongoDB Realm object.

Currently, CoSync AssetLink is tailored to function seamlessly with Amazon S3 bucket storage. However, in the future, CoSync has plans to expand its support to include additional storage providers such as Microsoft, Dropbox, and Google.

CoSyncStorage

The integration operates by leveraging a combination of MongoDB App Service server functions and a MongoDB Realm CoSync object, namely CoSyncAsset. The server functions, alongside the necessary access keys for Amazon S3 bucket storage, are configured within the MongoDB App Service through the CoSync Portal.

To initiate the upload of an asset to Amazon S3, the client-side program generates a call to the MongoDB function CosyncInitAsset() object that specifies and file path, and content type, and an expiration of the new asset. This will inform the App Service of the client’s intent, which will contact Amazon S3 and return the write URLs for the client to upload the asset to.

The notable advantage of the CoSync AssetLink solution lies in the direct transfer of asset data from the client device to the Amazon S3 bucket. This process bypasses the need to route through a MongoDB server and avoids consuming MongoDB bandwidth. Once the upload is successfully completed, the CoSync AssetLink protocol allows the client to notify the MongoDB App Service that the upload is complete and that an asset can be created around the uploaded data. To do this, the client will call the CosyncCreateAsset() function. In response the server will create asset read URLs and create a CosyncAsset object that wraps around them.

This setup process is straightforward and notably efficient, with the bulk of the work being performed at the client device’s edge rather than on the server side.

Asset upload process #

To trigger an asset upload, a client application commences the process by calling the CosyncInitAsset function with the MongoDB App Service. It’s important to note that the CoSync AssetLink module has been tailored to align with the MongoDB Flexible Sync model, as the older partition-based version has been deprecated.

To initiate an asset upload, the client application code is required to complete several key parameters: the filePath, the contentType, and the expirationHours.

async function CosyncInitAsset(
		filePath,           /* Input file path */
		contentType,        /* content MIME type for asset */
		expirationHours     /* Expiration in hours (0 means public) */
	)

The input filePath adheres to the following format:

	filePath := <directory>/<filename>.<extension>

Typically, the directory is assigned as either image, video, or audio to categorize the type of asset being uploaded. However, it’s important to note that developers have the flexibility to deviate from this convention. There is no strict constraint requiring it to be a single directory; it can also encompass a directory path, offering developers greater customization.

This function will return a JSON string. If successful, the return value will look as follows:

{
	statusCode : 200,
	contentId: <String>,
	writeUrls : {
		writeUrl : <String>,
		writeUrlSmall : <String>,
		writeUrlMedium : <String>,
		writeUrlLarge : <String>,
		writeUrlVideoPreview: <String>
	}
}

These write URLs are where the client will upload the asset data to. The contentId is used as a unique identifier to create the path on the Amazon S3 associated with the asset. The write URLs provided by the CoSync AssetLink service should always be used in conjunction with an HTTPS PUT command. It’s worth mentioning that, at present, the service does not support URLs for multipart HTTPS POST commands.

This path (which is computed by the App Service) specifies the location of the asset within the Amazon S3 bucket and adheres to the ensuing format:

	path := [public]<userId><directory>/<filename>-<contentId>.<extension>

In cases where the asset is designated as non-expiring, its path will be initialized with the ‘public/’ directory as a prefix. Furthermore, for a given input filePath, the backend will append a timestamp to the file name to safeguard against potential file conflicts. It’s worth noting that all paths are initially categorized based on the userId of the user initiating the asset upload. In simpler terms, all assets uploaded by John Smith, for instance, will be situated under a common root path associated with John Smith’s ‘userId/’ directory.

Assets can be categorized into two types: expiring and non-expiring (aka public). Expiring assets are characterized by an expirationHours property set to a positive value greater than zero, indicating the duration of their validity in hours. If expirationHours is set to zero, the asset is considered public and does not expire. In the case of non-expiring assets, their associated URL(s) remain perpetually valid and do not require periodic refreshment.

Expiring assets, on the other hand, offer enhanced security for customer asset data. For instance, an application may necessitate the creation of a URL containing sensitive information. To safeguard against unauthorized access, developers may opt to set an expiration period, such as 30 minutes, for the link. In the Amazon S3 storage system, non-expiring assets are stored in a public bucket, while expiring assets are housed in a private bucket. Consequently, a typical application will typically require two buckets to accommodate its asset storage needs.

Upon successful completion of the upload, the application client completes the asset creation process by calling the CreateCosyncAsset() function.

async function CosyncCreateAsset(
		filePath            /* Input file path */
		contentId,          /* contentId returned by CreateInitAsset() */
		contentType,        /* content MIME type for asset */
		expirationHours,    /* Expiration in hours (0 means public) */
		size,               /* size in bytes of asset */
		duration,           /* duration in seconds for video and audio assets */
		color,              /* HEX color for background of image */
		xRes,               /* x resolution in pixels of image asset */
		yRes,               /* y resolution in pixels of image asset */
		caption,            /* optional caption for asset */
		extra               /* extra information passed to CosyncAsset */
	)

This function will create a CosyncAsset object that wraps around the asset. This object will be readable by all, but only writable by the user who created the asset.

This function will return a JSON string. If successful, the return value will look as follows:

{
	statusCode : 200,
	asset: CosyncAsset
}

The asset is the CosyncAsset object that was created in the form of a JSON codable. Note: It is the responsibility of the client’s code to write the CosyncAsset to MongoDB Realm, so that it can sync with the rest of the application data.

The contentType property is employed to specify the content type of the asset, with various allowable values detailed in the Content Types table below.

The extra property serves as a container for additional information that the uploading client application code may need to store throughout the lifecycle of the CosyncAsset object. This information can be platform-specific in nature.

The following diagram presents a visual of the asset uploading process:

CosyncEngineStorage

The CoSync AssetLink services uses the MongoDB Realm third-party AWS Service to implement this functionality. It simply uses this service to compute the pre-signed URLs needed to upload and read asset information. The third-party service simply acts as a broker between MongoDB Realm and Amazon S3, while the CoSync AssetLink packages all of this into an easy to understand bundle that can be seamlessly integrated into a working client application.

Expiring Assets #

For security purposes, the CoSync AssetLink module allows a developer to control whether an asset’s URLs expires or not. Expiring URLs are used to protect sensitive assets from being shared over the Internet. Asset URLs can expire in a few hours (the default is 24) or in a few minutes depending on how sensitive the information is.

Asset expiration is controlled through the expirationHours property in the CosyncAssetUpload object at the time of the upload process. If an asset expires, the expirationHours property on the CosyncAsset object will set to a value greater than zero, and the expiration property will specify a date in UTC when the asset URLs expire. If an asset has expired, the client side code can call the function CosyncRefreshAsset(assetId) to force the backend to refresh the URLs for the asset. The new URLs that are computed will expire in so many expirationHours from the time the function was called.

The Cosync AssetLink module also supports non expiring assets. However, the developer should remember that URLs to non-expiring assets present a security risk should they be leaked to the wider Internet. On the other hand, there is one less management step for dealing with non-expiring assets.

To refresh an asset, a client can call the function CosyncRefreshAsset().

async function CosyncRefreshAsset(
		assetId			/* asset Id of the CosyncAsset object */
	)

Content Types #


    /* text asset type */
    "text/plain"
    "text/css"
    "text/richtext"
    "text/html"
    "text/xml"
    "text/tab-separated-values"
    "text/comma-separated-values"
    "text/x-vcard"
    "text/csv"
    "text/rtf"

    /* image asset type */
    "image/bmp"
    "image/gif"
    "image/jpeg"
    "image/png"
    "image/tiff"
    "image/ico"
    "image/vnd.adobe.photoshop"
    
    /* video asset type */
    "video/x-msvideo"
    "video/mpeg"
    "video/quicktime"
    "video/x-sgi-movie"
    "video/mp4"

    /* audio asset type */
    "audio/x-aiff"
    "audio/mpeg"
    "audio/x-pn-realaudio"
    "audio/basic"
    "audio/mid"
    "audio/x-wav"
    "audio/mp3"

    /* file asset type */
    "application/octet-stream"
    "application/msword"
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    "application/vnd.openxmlformats-officedocument.wordprocessingml.template"
    "application/vnd.ms-powerpoint"
    "application/vnd.openxmlformats-officedocument.presentationml.presentation"
    "application/vnd.openxmlformats-officedocument.presentationml.template"
    "application/vnd.openxmlformats-officedocument.presentationml.slideshow"
    "application/vnd.ms-excel"
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    "application/vnd.openxmlformats-officedocument.spreadsheetml.template"
    "application/vnd.ms-outlook"
    "application/vnd.ms-project"
    "application/x-msdownload"
    "application/zip"
    "application/postscript"
    "application/xml"
    "application/pdf"
    "application/x-dvi"
    "application/x-gtar"
    "application/x-tar"
    "application/x-gzip"
    "application/x-compress"
    "application/x-compressed"
    "application/illustrator"
    "application/x-shockwave-flash"
    "application/x-iwork-keynote-sffkey"
    "application/x-iwork-pages-sffpages"
    "application/x-iwork-numbers-sffnumbers"