|
|
|
package wopi
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
|
|
|
"fmt"
|
|
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ActonType string
|
|
|
|
|
|
|
|
var (
|
|
|
|
ActionPreview = ActonType("embedview")
|
|
|
|
ActionPreviewFallback = ActonType("view")
|
|
|
|
ActionEdit = ActonType("edit")
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
DiscoverResponseCacheKey = "wopi_discover"
|
|
|
|
DiscoverRefreshDuration = 24 * 3600 // 24 hrs
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c *client) AvailableExts() []string {
|
|
|
|
if err := c.checkDiscovery(); err != nil {
|
|
|
|
util.Log().Error("Failed to check WOPI discovery: %s", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
c.mu.RLock()
|
|
|
|
defer c.mu.RUnlock()
|
|
|
|
exts := make([]string, 0, len(c.actions))
|
|
|
|
for ext, actions := range c.actions {
|
|
|
|
_, previewable := actions[string(ActionPreview)]
|
|
|
|
_, editable := actions[string(ActionEdit)]
|
|
|
|
_, previewableFallback := actions[string(ActionPreviewFallback)]
|
|
|
|
|
|
|
|
if previewable || editable || previewableFallback {
|
|
|
|
exts = append(exts, strings.TrimPrefix(ext, "."))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return exts
|
|
|
|
}
|
|
|
|
|
|
|
|
// checkDiscovery checks if discovery content is needed to be refreshed.
|
|
|
|
// If so, it will refresh discovery content.
|
|
|
|
func (c *client) checkDiscovery() error {
|
|
|
|
c.mu.RLock()
|
|
|
|
if c.discovery == nil {
|
|
|
|
c.mu.RUnlock()
|
|
|
|
return c.refreshDiscovery()
|
|
|
|
}
|
|
|
|
|
|
|
|
c.mu.RUnlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// refresh Discovery action configs.
|
|
|
|
func (c *client) refreshDiscovery() error {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
|
|
|
|
cached, exist := c.cache.Get(DiscoverResponseCacheKey)
|
|
|
|
if exist {
|
|
|
|
cachedDiscovery := cached.(WopiDiscovery)
|
|
|
|
c.discovery = &cachedDiscovery
|
|
|
|
} else {
|
|
|
|
res, err := c.http.Request("GET", c.config.discoveryEndpoint.String(), nil).
|
|
|
|
CheckHTTPResponse(http.StatusOK).GetResponse()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to request discovery endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := xml.Unmarshal([]byte(res), &c.discovery); err != nil {
|
|
|
|
return fmt.Errorf("failed to parse response discovery endpoint: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := c.cache.Set(DiscoverResponseCacheKey, *c.discovery, DiscoverRefreshDuration); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// construct actions map
|
|
|
|
c.actions = make(map[string]map[string]Action)
|
|
|
|
for _, app := range c.discovery.NetZone.App {
|
|
|
|
for _, action := range app.Action {
|
|
|
|
if action.Ext == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := c.actions["."+action.Ext]; !ok {
|
|
|
|
c.actions["."+action.Ext] = make(map[string]Action)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.actions["."+action.Ext][action.Name] = action
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|