gionuibk's picture
Upload folder using huggingface_hub
61d39e2 verified
## Extensions - Implementing Drivers
Puter's concept of drivers has existed long before the extension system
was refined, and to keep things moving forward it has become easier to
develop Puter drivers in extensions than anywhere else in Puter's source.
If you want to build a driver, an extension is the recommended way to do it.
### What are Puter drivers?
Puter drivers are all called through the `/drivers/call` endpoint, so they
can be thought of as being "above" the HTTP layer. When a method on a driver
throws an error you will still receive a `200` HTTP status response because
the the invocation - from the HTTP layer - was successful.
A driver response follows this structure:
```json
{
"success": true,
"service": {
"name": "implementation-name"
},
"result": "any type of value goes here",
"metadata": {}
}
```
There exists an example driver called `hello-world`. This driver implements
a method called `greet` with the optional parameter `subject` which returns
a string greeting either `World` (default) or the specified subject.
```javascript
await puter.call('hello-world', 'no-frills', 'greet', { subject: 'Dave' });
```
Let's break it down:
#### `'hello-world'`
`'hello-world'` is the name of an "interface". An interface can be thought of
a contract of what inputs are allowed and what outputs are expected. For
example the `hello-world` interface specifies that there must be a method
called `greet` and it should return a string representing a greeting.
To add another example, an interface called `weather` specify a method called
`forcast5day` that always returns a list of 5 objects with a particular
structure.
#### `no-frills`
`'no-frills'` is a simple - "no frills" (nothing extra) - implementation of
the `hello-world` interface. All it does is return the string:
```javascript
`Hello, ${subject ?? 'World'}!`
```
#### `'greet'`
`greet` is the method being called. It's the only method on the `hello-world`
interface.
#### `{ subject: 'Dave' }`
These are the arguments to the `greet` method. The arguments specify that we
want to say "Hello" to Dave. Hopefully he doesn't ask us to open the pod bay
doors, or if he does we hopefully have extensions to add a driver interface
and driver implementation for the pod bay doors so that we can interact with
them.
### Drivers in Extensions
The `hellodriver` extension adds the `hello-world` interface like this:
```javascript
extension.on('create.interfaces', event => {
// createInterface is the only method on this `event`
event.createInterface('hello-world', {
description: 'Provides methods for generating greetings',
methods: {
greet: {
description: 'Returns a greeting',
parameters: {
subject: {
type: 'string',
optional: true
},
locale: {
type: 'string',
optional: true
},
}
}
}
})
});
```
The `hellodriver` extension adds the `no-frills` implementation for
`hello-world` like this:
```javascript
extension.on('create.drivers', event => {
event.createDriver('hello-world', 'no-frills', {
greet ({ subject }) {
return `Hello, ${subject ?? 'World'}!`;
}
});
});`
```
You can pass an instance of a class for a driver implementation as well:
```javascript
class Greeter {
greet ({ subject }) {
return `Hello, ${subject ?? 'World'}!`;
}
}
extension.on('create.drivers', event => {
event.createDriver('hello-world', 'no-frills', new Greeter());
});`
```
Instances of classes being supported
may seem to be implied by the example before this
one, but that is not the case. What's shown here is that function members
of the object passed to `createDriver` will not be "bound" (have their
`.bind()` method called with a different object as the instance variable).
### Permission Denied
When you try to access a driver as any user other than the default
`admin` user, it will not work unless permission has been granted.
The `hellodriver` extension grants permission to all clients using
the following snippet:
```javascript
extension.on('create.permissions', event => {
event.grant_to_everyone('service:no-frills:ii:hello-world');
});
```
The `create.permissions` event's `event` object has a few methods
you can use depending on the desired granularity:
- `grant_to_everyone` - grants permission to all users
- `grant_to_users` - grants permission to only registered users
(i.e. not to temporary/guest users)