Resource Manager

The PureWeb SDK's ResourceManager provides functionality which allows users to store and retrieve data. The data, which is stored on the service machine, can be anything that the service can copy as a ByteArray. This feature is commonly used in a collaborative session, when multiple users are connected to the same PureWeb session.

Since the SDK is designed to provide data security and keep clients very thin, the link to the resources is temporary: stored data is only available as long as the application session remains active.

 

The Resource Manager is primarily intended to facilitate the transfer service-side data to the client.

To transfer client-side data to the service, you would go a different route. Best practice will depend on the amount of data:

  • For a small amount of data, it may be possible to use commands: convert the data to a base64 encoded string, and pass it to the service application in the parameters object of the command.
  • For larger amounts of data, it may be best to use a different tool or mechanism such as side loading using FTP/SCP or cloud storage.

Overview

Data storage and retrieval is based on the unique identifier (GUID) key which the Resource Manager's store function automatically assigns to each resource:

  • In your service, you can define which GUID key to send to which client, and hence manage which clients have access to what files
  • All a client needs to retrieve a resource is the value for the GUID key; data retrieval is done using the RetrieveObject method
  • Clients can construct a URL from the GUID key and use this URL to access the resource directly (in iOS, Java and Android clients), or with a web browser; this is achieved by using the GetResourceURL method

It is possible for the service-side store function to save the same data in several different formats. This would be useful, for instance, to handle operating system differences. Consider for example the case of a collaborative text editing application. When saving the file in the Resource Manager, the service would save it in two different formats, let’s say a Windows-targeted .docx file and a .pages file for iOS-based clients. Each file format would be assigned its own GUID key; the key for the .docx files would be sent to the Windows clients, and the key to the .pages would be sent to the iOS-based clients.

Like most other communications between the service and the client, you can choose to use either commands or application state to provide to the clients the GUIDs associated with the stored data. With commands, the response only goes back to the client session that sent the command; writing the GUID in a descriptive path of application state allows the service to make the data available simultaneously to any and all clients.

The screen capture example below illustrates an implementation of the Resource Manager using commands.

  The Resource Manager currently has a 2 GB limit, due to how the RetrieveObject method in the various APIs retrieves the resources.

Example - Screen Captures

The code is in C++ for the service, and in Silverlight for the client.

To try this example yourself, edit the source code for the Scribble sample application. The necessary files are in the server installed directory:

  • Service: [installed_location]\SDK\Samples\Scribble\ScribbleAppCpp
  • Client: [installed_location]\SDK\Samples\Scribble\ScribbleClient

Service Code (Storing Data)

Assuming that the service will receive a command from the client application to save a screen capture (see client application code example further down), the service will first need a command handler, as shown below. (In the Scribble sample application, add the following code to the constructor in the ScribbleView.cpp file.):

CScribbleApp::StateManager().CommandManager().AddIoHandler("Save", Bind(this, &CScribbleView::OnExecuteSave));

This handler responds to the command Save by executing the OnExecuteSave method, shown below.

void CScribbleView::OnExecuteSave(CSI::Guid sessionId, CSI::Typeless command, CSI::Typeless response)
{
    PureWeb::Image image(m_pPixelBits, m_Width, m_Height, PureWeb::PixelFormat::Bgr24, PureWeb::ScanLineOrder::TopDown, 4);
    ByteArray jpeg = PureWeb::JpegEncoder::JpegCompress(image, 80);
    ContentInfo content("image/jpeg", jpeg.AsByteArray());
    Guid key = CScribbleApp::StateManager().ResourceManager().Store(content);
    response["ResourceKey"] = key;
}

This code:

  • creates an image given the current view’s pixel bits and dimensions (line 3) -- the variables m_pPixilBits, m_Width and m_Height are defined elsewhere in the Scribble sample code
  • converts the image into a JPEG (line 4),
  • packs the JPEG into a ContentInfo object (line 5),
  • stores the ContentInfo object into the application’s Resource Manager and returns a GUID (line 6),
  • returns the GUID as ResourceKey to the calling application (line 7).

Next, add a declaration of this new method in the header file (ScribbleView.h):

void OnExecuteSave(CSI::Guid sessionId, CSI::Typeless command, CSI::Typeless response);

Client Code (Retrieving Data)

On the client side, first add a button which, when clicked, will run the method to request a screen capture of the service application’s view; in this example, the method is called SaveButton_Click.

To create the button in the sample Silverlight client, add line 2 in the file MainPage.xaml.

<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="2" >
    <Button x:Name="save" Content="Save" Margin="4,3,0,3" Width="54" Click="SaveButton_Click"/>
</StackPanel>

Then, add the SaveButton_Click method to the MainPage.xaml.cs file. In this example, the code includes both the RetrieveObject and the GetResourceURL methods, for illustration purposes. The RetrieveObject method would be used internally by the program and does not display the retrieved resource to the end user. However, with the GetResourceURL method the user will be able to see the saved screen capture when the program runs:

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
    Framework.Instance.Client.QueueCommand("Save", (o, args) =>
    {
        if (args.Exception != null)
        {
            Trace.WriteLine("Except during RPC: " + args.Exception);
            return;
        }
        var key = args.Response.GetTextAs("ResourceKey", Guid.Empty);
         //section illustrating the the retrieveObject method
         var binaryObject = Framework.Instance.Client.RetrieveObject(key);
         var bitmapImage = new System.Windows.Media.Imaging.BitmapImage();

         using (var stream = new System.IO.MemoryStream(binaryObject.Object))
        {
             bitmapImage.SetSource(stream);
        }

        var image = new Image { Source = bitmapImage };
        //section illustrating the getResourceURL method
        var resourceUrlText = new TextBox { Text = Framework.Instance.Client.GetResourceUrl(key), IsReadOnly = true };

        var stackPanel = new StackPanel();
        stackPanel.Children.Add(resourceUrlText);
        stackPanel.Children.Add(image);

        var screenshotWindow = new ChildWindow { Title = "Screenshot image", Content = stackPanel };
        screenshotWindow.Show();
     });
}

This method:

  • queues the Save command and waits for a callback (line 3)
  • verifies, when the callback is received, that the storage was successful (line 5)
  • looks for the GUID saved in the ResourceKey response path, from the OnExecuteSave method on the service application (line 10)
  • uses the GUID to retrieve the binary representation of the saved image (line 12)
  • formats the binary object into a bitmap image (lines 13 - 20)
  • generates a unique URL which can be used to access the file indirectly with a web browser and places it into a text box (line 22)
  • creates a new Silverlight stack panel which contains the generated URL path in its text box and the saved image itself (lines 23- 26)
  • creates a child window which pops up and displays the new stack panel (lines 27 - 28)

After editing the sample Scribble application, when it runs next, try the new screen capture functionality:

There will be a new Save button in the Silverlight client. Click on it; the application will open a view on top of the current window, with the URL to the file and a presentation of the JPEG image. Copy and paste this link in a new window to retrieve the screen capture; this will work as long as the session remains active. Close the new view using the X in the top right corner.