There and back again:
Integrating widgets with device and user data
About the author
- Arve Bersvendsen ( arveb@opera.com )
- Opera Web Applications Team
This presentation
- DOM File IO
- JavaScript plugins
File IO: Rationale
- Allow more capable widgets
- … but with enforcable security constraints
- One unified way of accessing the file system
- On mobiles
- On the desktop
- On devices
File I/O features
- Sandboxed
- Synchronous (for the time being)
- Binary file support
Mountpoints
- The mountpoint is the sandbox
- The application only has access to the sandboxes
- Applications have access to a default private storage mountpoint
- … and (read-only) access to the application data itself
- Acquiring a mountpoint is done using the browseFor* methods:
browseForFile()
browseForDirectory()
- Can only be used as a result of non-synthetic UI events
- … much like a popup blocker works
- Mountpoints can be made persistent across invocations
Accessing files in a mountpoint
- The application needs no knowledge of the underlying file system conventions
- \ becomes /
- Almost any filename is permitted, but some are discouraged
- Symlinks are not followed
Discouraged characters
| Character |
Reason |
| : |
Used to denote alternate file streams on NTFS file systems, as a path
separator on OS X, and used to determine the mountpoint (e.g. C:) on
Windows systems.
|
| ? |
Used as a wildcard match on virtually all systems, and explicitly
illegal in filenames on Windows systems |
| * |
Used as a wildcard match on virtually all systems, and
explicitly illegal in filenames on Windows systems |
| |, < and > |
Used for pipes and redirection on Unix systems |
| \ |
Used as path separator on Windows systems |
The ':' problem
- createDirectory('http://foo/bar')
- http: / foo / bar <- In Linux
- http / foo / bar <- In OS X
Discouraged filenames
- CON, PRN, AUX, CLOCK$, NUL, COM0, COM1, COM2, COM3, COM4, COM5,
COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6,
LPT7, LPT8, and LPT9.
- Thank you, MS-DOS.
The mountpoint protocol
mountpoint://mountpoint_name/path/to/file
- Works with regular filesystem operations
- … or in HTML, XMLHttpRequest and friends
File I/O in relation to widgets
- The application authors opts in for access:
<widget file="yes">
- We are proposing a more generic syntax for extended APIs
The API
window is polluted enough
- We've placed a filesystem singleton on
opera.io
Mounting
opera.io.filesystem.browseForDirectory(
"someName", // mountpoint://someName/path/to/file
"",
myCallback,
false)
Mounting
opera.io.filesystem.browseForDirectory(
"someName", // mountpoint://someName/path/to/file
"", // Where to start browsing
myCallback,
false)
Mounting
opera.io.filesystem.browseForDirectory(
"someName", // mountpoint://someName/path/to/file
"", // Where to start browsing
myCallback, // called with file when mount is successful
false)
Mounting
opera.io.filesystem.browseForDirectory(
"someName", // mountpoint://someName/path/to/file
"", // Where to start browsing
myCallback, // called with file when mount is successful
false) // Persistent?
Mounting, continued
mountSystemDirectory() allows mounting a couple of preset directories
- Takes one argument, a DOMString
- "application": gives you access to the application's own files. Read-only
- "storage": Private storage area for the application. Read-write
- Does not require user interaction, like browse* methods
Unmounting
removeMountPoint()
- Takes a string or file
Working with files
- A mountpoint is a
File object
- A folder is a
File object
- A zip archive is a
File object
- … incidentally, so are files
Working with files
var file, files = opera.io.filesystem.mountPoints["someName"];
files.refresh(); // The mountpoint is not live
for (var i = 0; file = files[i]; i++)
{
if (file.isDirectory)
{
// Do something to the directory
}
else
{
doSomething(file); // Do something to the file
}
}
Opening files
- File.open()
- Two ways
- Strings
- … or by passing a file object
Opening files
function doSomething(file)
{
var myStream = files.open(file, "r");
}
- The second argument to
open() is similar to what you'd recognize
from your average C/C++ : "r", "r+", "w", "w+", "a"
- We might like to change that, though.
Creating files
var myStream = files.open("somenonexistentfile","w");
or:
var file = files.resolve("somenonexistentfile");
var myStream = files.open(file,"w");
Working with the stream
- The
FileStream interface is mixed mode ASCII/binary
- read/readLine read character data in some well-defined encoding
- write/writeLine does the same
- ... currently, the well-defined encoding is only UTF-8, but this is a known bug
Working with the stream
- For binary, we stole the ByteArray from ECMAScript 4
readBytes()
- (
readBase64() and writeBase64() should you need it
writeBytes(), writeImage() and writeFile()
A primitive copyFile implementation
function copyFile( f1, f2 )
{
var srcStream = f2.open(f2,"r");
var destStream = f1.open(f1,"rw");
var srcData = srcStream.read(f2.fileSize);
srcStream.close();
destStream.writeBytes(srcData);
destStream.close();
}
- This is reduntant, though.
File objects have copyTo and moveTo
Known issues
- Ill-defined exceptions
- Asynchronous file I/O is missing
- Feedback is extremely welcome
A few words about JavaScript plugins
- Name is not immediately revealing
- Used to extend the functionality of the browser
- Written in mostly plain old C
- Allows you to extend the Opera runtime with functionality
otherwise not possible
- Two years ago, Håkon demoed an application that read
accelerometer data from a Thinkpad, to play a game
- We are considering taking this in to widgets
- Allow custom APIs for special uses: iTunes, location APIs etc.
Standards: Widgets
- We're currently using
<widget file="yes"> in the manifest
- We might however like something like the example below
<widget xmlns="http://www.w3.org/ns/widgets"
id="http://datadriven.com.au/exampleWidget">
<api src="http://example.com/fileIO/2.0" optional="optional">
<api src="http://example.com/fileIO/2.0"></api>
</api>
</widget>
Questions?