mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-07-19 20:14:17 -04:00
Merge pull request #2182 from owncloud/extension_development
[docs-only] extension development
This commit is contained in:
@@ -7,227 +7,59 @@ geekdocEditPath: edit/master/docs/ocis/development
|
||||
geekdocFilePath: extensions.md
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
oCIS is all about files, sync and share - but most of the time there is more you want to do with your files, e.g. having a different view on your photo collection or editing your offices files in an online file editor. ownCloud 10 faced the same problem and solved it with `applications`, which can extend the functionality of ownCloud 10 in a wide range. Since oCIS is different in its architecture compared to ownCloud 10, we had to come up with a similiar (yet slightly different) solution. To extend the functionality of oCIS, you can write or install `extensions`. An extension is basically any running code which integrates into oCIS and provides functionality to oCIS and its users. Because extensions are just microservices providing an API, you can technically choose any programming language you like - a huge improvement to ownCloud 10, where it was nearly impossible to use a different programming language than PHP.
|
||||
|
||||
## How to build and run ocis-simple
|
||||
We will now introduce you to the oCIS extension system and show you how you can create a custom extension yourself.
|
||||
|
||||
oCIS uses build tags to build different flavors of the binary. In order to work on a new extension we are going to reduce the scope a little and use the `simple` tag. Let us begin by creating a dedicated folder:
|
||||
## Extension examples
|
||||
|
||||
```console
|
||||
mkdir ocis-extension-workshop && ocis-extension-workshop
|
||||
```
|
||||
Technically every service in oCIS is an extension, even if oCIS would not really work without some of them. Therefore, you can draw inspiration from any of the plenty of extensions in the [oCIS monorepo](https://github.com/owncloud/ocis).
|
||||
|
||||
Following https://github.com/owncloud/ocis
|
||||
Besides these "default" extensions in the oCIS monorepo, there are two more extensions you should be aware of:
|
||||
|
||||
```console
|
||||
git clone https://github.com/owncloud/ocis.git
|
||||
cd ocis
|
||||
- [Hello](https://github.com/owncloud/ocis-hello)
|
||||
- [WOPI server](https://github.com/owncloud/ocis-wopiserver)
|
||||
|
||||
TAGS=simple make generate build
|
||||
```
|
||||
Differences between the extensions maintained inside the oCIS monorepo and the ones maintained in their own repository are:
|
||||
|
||||
*Q: Can you specify which version of ownCloud Web to use?*
|
||||
*A: No, the ownCloud Web that is used is compiled into the [assets of ocis-web](https://github.com/owncloud/ocis/blob/master/web/pkg/assets/embed.go) which is currently not automatically updated. We'll see how to use a custom ownCloud Web later.*
|
||||
- extensions inside the [oCIS monorepo](https://github.com/owncloud/ocis) are all written in Go, whereas other extensions may choose the programming language freely
|
||||
- extensions inside the oCIS monorepo heavily share tooling to reduce maintenance efforts, whereas other extensions may use different tooling (e.g. a different CI system)
|
||||
- extensions inside the oCIS monorepo will be all build into one binary and started with the `ocis server` command. All other extensions must be started individually besides oCIS.
|
||||
|
||||
`bin/ocis server`
|
||||
|
||||
Open the browser at https://localhost:9200
|
||||
For quickstart purposes we also offer a [template project](https://github.com/owncloud/boilr-ocis-extension) which can be used to generate all the boilerplate code for you. But you also can decide to use your own project layout or even a different programming language.
|
||||
|
||||
1. You land on the login screen. click login
|
||||
2. You are redirected to an idp at https://localhost:9200/signin/v1/identifier with a login mask. Use `einstein:relativity` (one of the three demo users) to log in
|
||||
3. You are redirected to http://localhost:9100/#/hello the ocis-hello app
|
||||
4. Replace `World` with something else and submit. You should see `Hello %something else%`
|
||||
|
||||
*Q: One of the required ports is already in use. Ocis seems to be trying to restart the service over and over. What gives?*
|
||||
*A: Using the ocis binary to start the server will case ocis to keep track of the different services and restart them in case they crash.*
|
||||
## Integration into oCIS
|
||||
|
||||
## Hacking ocis-hello
|
||||
|
||||
go back to the ocis-extension-workshop folder
|
||||
|
||||
```console
|
||||
cd ..
|
||||
```
|
||||
|
||||
Following https://github.com/owncloud/ocis-hello
|
||||
|
||||
```
|
||||
git clone https://github.com/owncloud/ocis-hello.git
|
||||
cd ocis-hello
|
||||
|
||||
yarn install
|
||||
# this actually creates the assets
|
||||
yarn build
|
||||
|
||||
# this will compile the assets into the binary
|
||||
make generate build
|
||||
```
|
||||
|
||||
Two options:
|
||||
1. run only the necessary services from ocis and ocis-hello independently
|
||||
2. compile ocis with the updated ocis-hello
|
||||
|
||||
### Option 1:
|
||||
get a list of ocis services:
|
||||
|
||||
```console
|
||||
ps ax | grep ocis
|
||||
```
|
||||
|
||||
Try to kill `ocis hello`
|
||||
|
||||
Remember: For now, killing a service will cause ocis to restart it. This is subject to change.
|
||||
|
||||
In order to be able to manage the processes ourselves we need to start them independently:
|
||||
|
||||
`bin/ocis server` starts the same services as:
|
||||
|
||||
```
|
||||
bin/ocis micro &
|
||||
bin/ocis web &
|
||||
bin/ocis hello &
|
||||
bin/ocis reva &
|
||||
```
|
||||
|
||||
Now we can kill the `ocis hello` and use our custom built ocis-hello binary:
|
||||
|
||||
```console
|
||||
cd ../ocis-hello
|
||||
bin/ocis-hello server
|
||||
```
|
||||
|
||||
## Hacking ownCloud Web (and ocis-web)
|
||||
|
||||
Following https://github.com/owncloud/web we are going to build the current ownCloud Web
|
||||
|
||||
```
|
||||
git clone https://github.com/owncloud/web.git
|
||||
cd web
|
||||
|
||||
yarn install
|
||||
yarn dist
|
||||
```
|
||||
|
||||
We can tell ocis to use the compiled assets:
|
||||
|
||||
Kill `ocis web`, then use the compiled assets when starting ownCloud Web.
|
||||
|
||||
```console
|
||||
cd ../ocis
|
||||
WEB_ASSET_PATH="`pwd`/../web/dist" bin/ocis web
|
||||
```
|
||||
|
||||
## The ownCloud design system
|
||||
|
||||
The [ownCloud design system](https://owncloud.design/) contains a set of ownCloud vue components for ownCloud Web or your own ocis extensions. Please use it for a consistent look and feel.
|
||||
|
||||
## External ownCloud Web apps
|
||||
|
||||
This is what hello is: copy and extend!
|
||||
|
||||
1. ownCloud Web is configured using the config.json which is served by the ocis-web service (either `bin/ocis web` or `bin/web server`)
|
||||
|
||||
2. point ocis-web to the web config which you extended with an external app:
|
||||
`WEB_UI_CONFIG="`pwd`/../web/config.json" ASSET_PATH="`pwd`/../web/dist" bin/ocis web`
|
||||
|
||||
```json
|
||||
{
|
||||
"server": "https://localhost:9200",
|
||||
"theme": "owncloud",
|
||||
"version": "0.1.0",
|
||||
"openIdConnect": {
|
||||
"metadata_url": "https://localhost:9200/.well-known/openid-configuration",
|
||||
"authority": "https://localhost:9200",
|
||||
"client_id": "web",
|
||||
"response_type": "code",
|
||||
"scope": "openid profile email"
|
||||
},
|
||||
"apps": [],
|
||||
"external_apps": [
|
||||
{
|
||||
"id": "hello",
|
||||
"path": "http://localhost:9105/hello.js",
|
||||
"config": {
|
||||
"url": "http://localhost:9105"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "myapp",
|
||||
"path": "http://localhost:6789/superapp.js",
|
||||
"config": {
|
||||
"backend": "http://someserver:1234",
|
||||
"myconfig": "is awesome"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## ownCloud Web extension points
|
||||
|
||||
{{< hint info >}}
|
||||
For an up to date list check out [the ownCloud Web documentation](https://github.com/owncloud/web/issues/2423).
|
||||
{{< /hint >}}
|
||||
|
||||
Several ones available:
|
||||
Depending on the functionality of your extension, you might need to integrate with one or multiple of the components of oCIS mentioned below.
|
||||
|
||||
### ownCloud Web
|
||||
- App switcher (defined in config.json)
|
||||
- App container (loads UI of your extension)
|
||||
|
||||
### Files app
|
||||
- File action
|
||||
- Create new file action
|
||||
- Sidebar
|
||||
- Quick access for sidebar inside of file actions (in the file row)
|
||||
If your extension is not just doing something in the background, you will need a UI in order to allow the user to interact with your extension. You could just provide your own web frontend for that purpose, but for a better user experience you can easily integrate into the web frontend of oCIS, the new [ownCloud Web](https://github.com/owncloud/web).
|
||||
|
||||
Example of a file action in the `app.js`:
|
||||
```js
|
||||
const appInfo = {
|
||||
name: 'MarkdownEditor',
|
||||
id: 'markdown-editor',
|
||||
icon: 'text',
|
||||
isFileEditor: true,
|
||||
extensions: [{
|
||||
extension: 'txt',
|
||||
newFileMenu: {
|
||||
menuTitle ($gettext) {
|
||||
return $gettext('Create new plain text file…')
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extension: 'md',
|
||||
newFileMenu: {
|
||||
menuTitle ($gettext) {
|
||||
return $gettext('Create new mark-down file…')
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
ownCloud Web allows you to write an extension for itself and therefore offers a seamless user experience. Upon login, the user will be able to use the application switcher to switch between the files view, settings and other available and installed extensions, yours included. Furthermore it is also possible to register your extension for different file actions. As an example, you could offer your extension to the user for creating and editing office documents. The user will then be able to create or open a file with your application directly from the files view. How to provide create an extension for ownCloud Web can be seen best in [the Hello extension](https://github.com/owncloud/ocis-hello/blob/master/ui/app.js), whereas plain file handling without any web frontend is available in the [WOPI server extension](https://github.com/owncloud/ocis-wopiserver/blob/master/ui/app.js).
|
||||
|
||||
For the side bar have a look at the files app, `defaults.js` & `fileSideBars`
|
||||
To make ownCloud Web pick up your extension, you need to activate it in the configuration like seen in the [Hello extension](https://owncloud.dev/extensions/ocis_hello/running/#configure-and-start-ocis).
|
||||
|
||||
## API driven development
|
||||
For a consistent look and feel, ownCloud Web uses a external design library, the [ownCloud design system](https://github.com/owncloud/owncloud-design-system). Since its classes and components are available through the wrapping `web runtime`, we highly recommend you to leverage it in your extension as well.
|
||||
|
||||
Until now we only had a look at the ui and how the extensions are managed on the cli. But how do apps actually talk to the server?
|
||||
### Settings
|
||||
|
||||
Short answer: any way you like
|
||||
An extension likely has some behaviour which the user can configure. Fundamental configuration will often be done by administrators during deployment, via configuration files or by setting environment variables. But for other settings, which are supposed to change more often or which are even user specific, this is not a viable way. Therefore you need to offer the users a UI where they can configure your extension to their liking. Because implementing something like this is a repetitive task among extensions, oCIS already offers the settings extensions which does that for your extension. Your extension just needs to register settings bundles, respective permissions and finally read the current values from the settings service. You can read more on that on the [settings extension]({{< ref "../../extensions/settings" >}}) and see how [oCIS Hello uses these settings](https://owncloud.dev/extensions/ocis_hello/settings/).
|
||||
|
||||
Long answer: micro and ocis-hello follow a protocol driven development:
|
||||
### Proxy
|
||||
|
||||
- specify the API using protobuf
|
||||
- generate client and server code
|
||||
- evolve based on the protocol
|
||||
The Proxy is an API gateway and acts as the single connection point where all external request from users and devices need to pass through.
|
||||
|
||||
- CS3 api uses protobuf as well and uses GRPC
|
||||
To make sure that requests can reach your extension's API, you need to register one or multiple endpoints at the proxy. The registration is a easy task and can be seen best on the [oCIS Hello example](https://owncloud.dev/extensions/ocis_hello/running/#configure-and-start-ocis).
|
||||
|
||||
- ocis uses go-micro, which provides http and grpc gateways
|
||||
- the gateways and protocols are optional
|
||||
As files in ownCloud must always stay private (unless you share them with your friends or coworkers), requests to oCIS have an authenticated user context. This user context is also available to your extension and can be used to interact with the user's files. How to get the user context and authentication can be seen on the [oCIS Hello example](https://owncloud.dev/extensions/ocis_hello/settings/#account-uuid).
|
||||
|
||||
- owncloud and kopano are looking into a [MS graph](https://developer.microsoft.com/de-de/graph) like api to handle ownCloud Web requests.
|
||||
- they might be about user, contacts, calendars ... which is covered by the graph api
|
||||
- we want to integrate with eg. kopano and provide a common api (file sync and share is covered as well)
|
||||
### Storage
|
||||
|
||||
- as an example for protobuf take a look at [ocis-hello](https://github.com/owncloud/ocis-hello/tree/master/pkg/proto/v0)
|
||||
oCIS leverages the CS3 APIs and [CS3 REVA](https://github.com/cs3org/reva) as a storage system because it offers a very flexible setup and supports a variety of storage backends like EOS, S3 and of course your local hard drive. REVA makes it easy to support more storage backends as needed.
|
||||
|
||||
If you need to interact with files directly, you have the full power of the [CS3 APIs](https://cs3org.github.io/cs3apis/) in your hand. With the user context and the user's authentication token, which your extensions gets from the proxy, your extension can make these request in behalf of the user.
|
||||
|
||||
If your extension needs to store persistent data which is not supposed to live in the user's home folder, there is also a so-called metadata storage, intended for exactly that purpose. You should always use the metadata storage in favor of the local filesystem for persistent files, because your extension will then automatically use the storage backend the oCIS admin decides to use. For a temporary cache it is perfectly fine to use the local filesystem.
|
||||
|
||||
Reference in New Issue
Block a user