github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/wopi/discovery.go (about) 1 package wopi 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "github.com/cloudreve/Cloudreve/v3/pkg/util" 7 "net/http" 8 "strings" 9 ) 10 11 type ActonType string 12 13 var ( 14 ActionPreview = ActonType("embedview") 15 ActionPreviewFallback = ActonType("view") 16 ActionEdit = ActonType("edit") 17 ) 18 19 const ( 20 DiscoverResponseCacheKey = "wopi_discover" 21 DiscoverRefreshDuration = 24 * 3600 // 24 hrs 22 ) 23 24 func (c *client) AvailableExts() []string { 25 if err := c.checkDiscovery(); err != nil { 26 util.Log().Error("Failed to check WOPI discovery: %s", err) 27 return nil 28 } 29 30 c.mu.RLock() 31 defer c.mu.RUnlock() 32 exts := make([]string, 0, len(c.actions)) 33 for ext, actions := range c.actions { 34 _, previewable := actions[string(ActionPreview)] 35 _, editable := actions[string(ActionEdit)] 36 _, previewableFallback := actions[string(ActionPreviewFallback)] 37 38 if previewable || editable || previewableFallback { 39 exts = append(exts, strings.TrimPrefix(ext, ".")) 40 } 41 } 42 43 return exts 44 } 45 46 // checkDiscovery checks if discovery content is needed to be refreshed. 47 // If so, it will refresh discovery content. 48 func (c *client) checkDiscovery() error { 49 c.mu.RLock() 50 if c.discovery == nil { 51 c.mu.RUnlock() 52 return c.refreshDiscovery() 53 } 54 55 c.mu.RUnlock() 56 return nil 57 } 58 59 // refresh Discovery action configs. 60 func (c *client) refreshDiscovery() error { 61 c.mu.Lock() 62 defer c.mu.Unlock() 63 64 cached, exist := c.cache.Get(DiscoverResponseCacheKey) 65 if exist { 66 cachedDiscovery := cached.(WopiDiscovery) 67 c.discovery = &cachedDiscovery 68 } else { 69 res, err := c.http.Request("GET", c.config.discoveryEndpoint.String(), nil). 70 CheckHTTPResponse(http.StatusOK).GetResponse() 71 if err != nil { 72 return fmt.Errorf("failed to request discovery endpoint: %w", err) 73 } 74 75 if err := xml.Unmarshal([]byte(res), &c.discovery); err != nil { 76 return fmt.Errorf("failed to parse response discovery endpoint: %w", err) 77 } 78 79 if err := c.cache.Set(DiscoverResponseCacheKey, *c.discovery, DiscoverRefreshDuration); err != nil { 80 return err 81 } 82 } 83 84 // construct actions map 85 c.actions = make(map[string]map[string]Action) 86 for _, app := range c.discovery.NetZone.App { 87 for _, action := range app.Action { 88 if action.Ext == "" { 89 continue 90 } 91 92 if _, ok := c.actions["."+action.Ext]; !ok { 93 c.actions["."+action.Ext] = make(map[string]Action) 94 } 95 96 c.actions["."+action.Ext][action.Name] = action 97 } 98 } 99 100 return nil 101 }