Init V4 community edition (#2265)

* Init V4 community edition

* Init V4 community edition
This commit is contained in:
AaronLiu
2025-04-20 17:31:25 +08:00
committed by GitHub
parent da4e44b77a
commit 21d158db07
597 changed files with 119415 additions and 41692 deletions

View File

@@ -3,9 +3,9 @@ package wopi
import (
"encoding/xml"
"fmt"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"net/http"
"strings"
"github.com/cloudreve/Cloudreve/v4/pkg/setting"
"github.com/gofrs/uuid"
"github.com/samber/lo"
)
type ActonType string
@@ -16,86 +16,53 @@ var (
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
func DiscoveryXmlToViewerGroup(xmlStr string) (*setting.ViewerGroup, error) {
var discovery WopiDiscovery
if err := xml.Unmarshal([]byte(xmlStr), &discovery); err != nil {
return nil, fmt.Errorf("failed to parse WOPI discovery XML: %w", err)
}
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, "."))
}
group := &setting.ViewerGroup{
Viewers: make([]setting.Viewer, 0, len(discovery.NetZone.App)),
}
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)
for _, app := range discovery.NetZone.App {
viewer := setting.Viewer{
ID: uuid.Must(uuid.NewV4()).String(),
DisplayName: app.Name,
Type: setting.ViewerTypeWopi,
Icon: app.FavIconUrl,
WopiActions: make(map[string]map[setting.ViewerAction]string),
}
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)
if _, ok := viewer.WopiActions[action.Ext]; !ok {
viewer.WopiActions[action.Ext] = make(map[setting.ViewerAction]string)
}
c.actions["."+action.Ext][action.Name] = action
if action.Name == string(ActionPreview) {
viewer.WopiActions[action.Ext][setting.ViewerActionView] = action.Urlsrc
} else if action.Name == string(ActionPreviewFallback) {
viewer.WopiActions[action.Ext][setting.ViewerActionView] = action.Urlsrc
} else if action.Name == string(ActionEdit) {
viewer.WopiActions[action.Ext][setting.ViewerActionEdit] = action.Urlsrc
} else if len(viewer.WopiActions[action.Ext]) == 0 {
delete(viewer.WopiActions, action.Ext)
}
}
viewer.Exts = lo.MapToSlice(viewer.WopiActions, func(key string, value map[setting.ViewerAction]string) string {
return key
})
if len(viewer.WopiActions) > 0 {
group.Viewers = append(group.Viewers, viewer)
}
}
return nil
return group, nil
}