docs: add code documentation

This commit is contained in:
Juan Pablo Villafáñez
2024-03-25 11:22:19 +01:00
parent 5c85daa06c
commit d85d24b5c5
9 changed files with 124 additions and 2 deletions

View File

@@ -1,5 +1,9 @@
package connector
// ConnectorError defines an error in the connector. It contains an error code
// and a message.
// For convenience, the error code can be used as HTTP error code, although
// the connector shouldn't know anything about HTTP.
type ConnectorError struct {
HttpCodeOut int
Msg string
@@ -16,6 +20,15 @@ func NewConnectorError(code int, msg string) *ConnectorError {
}
}
// Connector will implement the WOPI operations.
// For convenience, the connector splits the operations based on the
// WOPI endpoints, so you'll need to get the specific connector first.
//
// Available endpoints:
// * "Files" -> GetFileConnector()
// * "File contents" -> GetContentConnector()
//
// Other endpoints aren't available for now.
type Connector struct {
fileConnector *FileConnector
contentConnector *ContentConnector

View File

@@ -18,6 +18,10 @@ import (
"github.com/rs/zerolog"
)
// ContentConnector implements the "File contents" endpoint.
// Basically, the ContentConnector handles downloads (GetFile) and
// uploads (PutFile)
// Note that operations might return any kind of error, not just ConnectorError
type ContentConnector struct {
gwc gatewayv1beta1.GatewayAPIClient
cfg *config.Config
@@ -32,6 +36,13 @@ func NewContentConnector(gwc gatewayv1beta1.GatewayAPIClient, cfg *config.Config
// GetFile downloads the file from the storage
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/getfile
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// The contents of the file will be written directly into the writer passed as
// parameter.
func (c *ContentConnector) GetFile(ctx context.Context, writer io.Writer) error {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {
@@ -138,6 +149,24 @@ func (c *ContentConnector) GetFile(ctx context.Context, writer io.Writer) error
// PutFile uploads the file to the storage
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/putfile
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// The contents of the file will be read from the stream. The full stream
// length must be provided in order to upload the file.
//
// A lock ID must be provided for the upload (which must match the lock in the
// file). The only case where an empty lock ID can be used is if the target
// file has 0 size.
//
// This method will return the lock ID that should be returned in case of a
// conflict, otherwise it will return an empty string. This means that if the
// method returns a ConnectorError with code 409, the returned string is the
// lock ID that should be used in the X-WOPI-Lock header. In other error
// cases or if the method is successful, an empty string will be returned
// (check for err != nil to know if something went wrong)
func (c *ContentConnector) PutFile(ctx context.Context, stream io.Reader, streamLength int64, lockID string) (string, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {

View File

@@ -38,6 +38,14 @@ func NewFileConnector(gwc gatewayv1beta1.GatewayAPIClient, cfg *config.Config) *
// GetLock returns a lock or an empty string if no lock exists
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/getlock
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// The lock ID applied to the file reference in the context will be returned
// (if any). An error will be returned if something goes wrong. The error
// could be a ConnectorError
func (f *FileConnector) GetLock(ctx context.Context) (string, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {
@@ -80,6 +88,21 @@ func (f *FileConnector) GetLock(ctx context.Context) (string, error) {
// Lock returns a WOPI lock or performs an unlock and relock
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/lock
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/unlockandrelock
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// Lock the file reference contained in the context with the provided lockID.
// The oldLockID is only used for the "unlock and relock" operation. The "lock"
// operation doesn't use the oldLockID and needs to be empty in this case.
//
// For the "lock" operation, if the operation is successful, an empty lock id
// will be returned without any error. In case of conflict, the current lock
// id will be returned along with a 409 ConnectorError. For any other error,
// the method will return an empty lock id.
//
// For the "unlock and relock" operation, the behavior will be the same.
func (f *FileConnector) Lock(ctx context.Context, lockID, oldLockID string) (string, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {
@@ -207,6 +230,17 @@ func (f *FileConnector) Lock(ctx context.Context, lockID, oldLockID string) (str
// RefreshLock refreshes a provided lock for 30 minutes
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/refreshlock
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// If the operation is successful, an empty lock id will be returned without
// any error. In case of conflict, the current lock id will be returned
// along with a 409 ConnectorError. For any other error, the method will
// return an empty lock id.
// The conflict happens if the provided lockID doesn't match the one actually
// applied in the target file.
func (f *FileConnector) RefreshLock(ctx context.Context, lockID string) (string, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {
@@ -304,6 +338,17 @@ func (f *FileConnector) RefreshLock(ctx context.Context, lockID string) (string,
// UnLock removes a given lock from a file
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/unlock
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// If the operation is successful, an empty lock id will be returned without
// any error. In case of conflict, the current lock id will be returned
// along with a 409 ConnectorError. For any other error, the method will
// return an empty lock id.
// The conflict happens if the provided lockID doesn't match the one actually
// applied in the target file.
func (f *FileConnector) UnLock(ctx context.Context, lockID string) (string, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {
@@ -389,6 +434,13 @@ func (f *FileConnector) UnLock(ctx context.Context, lockID string) (string, erro
// CheckFileInfo returns information about the requested file and capabilities of the wopi server
// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo
//
// The context MUST have a WOPI context, otherwise an error will be returned.
// You can pass a pre-configured zerologger instance through the context that
// will be used to log messages.
//
// If the operation is successful, a "FileInfo" instance will be returned,
// otherwise the "FileInfo" will be empty and an error will be returned.
func (f *FileConnector) CheckFileInfo(ctx context.Context) (FileInfo, error) {
wopiContext, err := middleware.WopiContextFromCtx(ctx)
if err != nil {

View File

@@ -1,5 +1,11 @@
package connector
// FileInfo contains the properties of the file.
// Some properties refer to capabilities in the WOPI client, and capabilities
// that the WOPI server has.
//
// For now, the FileInfo contains data for Microsoft, Collabora and OnlyOffice.
// Not all the properties are supported by every system.
type FileInfo struct {
// ------------
// Microsoft WOPI check file info specification:

View File

@@ -15,6 +15,14 @@ const (
HeaderWopiOldLock string = "X-WOPI-OldLock"
)
// HttpAdapter will adapt the responses from the connector to HTTP.
//
// The adapter will use the request's context for the connector operations,
// this means that the request MUST have a valid WOPI context and a
// pre-configured logger. This should have been prepared in the routing.
//
// All operations are expected to follow the definitions found in
// https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/endpoints
type HttpAdapter struct {
con *Connector
}

View File

@@ -8,6 +8,10 @@ import (
var commonCS3ApiClient gatewayv1beta1.GatewayAPIClient
// GatewayAPIClient gets an instance based on the provided configuration.
// The instance will be cached and returned if possible, unless the "forceNew"
// parameter is set to true. In this case, the old instance will be replaced
// with the new one if there is no error.
func GetCS3apiClient(cfg *config.Config, forceNew bool) (gatewayv1beta1.GatewayAPIClient, error) {
// establish a connection to the cs3 api endpoint
// in this case a REVA gateway, started by oCIS

View File

@@ -14,11 +14,20 @@ import (
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
)
// RegisterOcisService will register this service.
// There are no explicit requirements for the context, and it will be passed
// without changes to the underlying RegisterService method.
func RegisterOcisService(ctx context.Context, cfg *config.Config, logger log.Logger) error {
svc := registry.BuildGRPCService(cfg.Service.Name, uuid.Must(uuid.NewV4()).String(), cfg.GRPC.Addr, "0.0.0")
return registry.RegisterService(ctx, svc, logger)
}
// RegisterAppProvider will register this service as app provider in REVA.
// The GatewayAPIClient is expected to be provided via `helpers.GetCS3apiClient`.
// The appUrls are expected to be provided via `helpers.GetAppURLs`
//
// Note that this method doesn't provide a re-registration mechanism, so it
// will register the service once
func RegisterAppProvider(
ctx context.Context,
cfg *config.Config,

View File

@@ -39,7 +39,7 @@ func Config(val *config.Config) Option {
}
}
// ViewUrl provides a function to set the ViewUrl option.
// AppURLs provides a function to set the AppURLs option.
func AppURLs(val map[string]map[string]string) Option {
return func(o *Options) {
o.AppURLs = val

View File

@@ -21,6 +21,7 @@ import (
"github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware"
)
// NewHandler creates a new grpc service implementing the OpenInApp interface
func NewHandler(opts ...Option) (*Service, func(), error) {
teardown := func() {}
options := newOptions(opts...)
@@ -39,7 +40,7 @@ func NewHandler(opts ...Option) (*Service, func(), error) {
}, teardown, nil
}
// Service implements the searchServiceHandler interface
// Service implements the OpenInApp interface
type Service struct {
id string
appURLs map[string]map[string]string