File size: 4,826 Bytes
61d39e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
## 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)