Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial version of the search extension #3635

Merged
merged 56 commits into from
May 2, 2022
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
3099d4a
Add an initial version of a search service.
aduffeck Apr 8, 2022
6cc0487
Also store (and return) the Size in the index
aduffeck Apr 8, 2022
0768aef
Use NewQueryStringQuery to allow for using wildcards etc.
aduffeck Apr 11, 2022
79035ba
Store and return the path. Add more tests
aduffeck Apr 11, 2022
099a89a
Limit the search to the directory specified in the reference
aduffeck Apr 11, 2022
a0890eb
Implement Remove for removing entries from the index
aduffeck Apr 11, 2022
6f59395
Cleanup
aduffeck Apr 11, 2022
6bb9af5
allow proxy to route based on request method
butonic Apr 12, 2022
6be2d8c
Add protobuf definitions and use those instead of our structs
aduffeck Apr 12, 2022
f232923
webdav: handle REPORT
butonic Apr 13, 2022
9535b73
Merge branch 'master' into search
butonic Apr 13, 2022
4c23ced
Fix the index after the protobuf refactoring
aduffeck Apr 13, 2022
a737f4e
Fix type, hook up proper service
aduffeck Apr 13, 2022
b4017a0
minimal report handling
butonic Apr 13, 2022
ab2a4e7
fix nil
butonic Apr 13, 2022
997cfc2
Limit the search to the specified space in the reference
aduffeck Apr 14, 2022
6573c2a
check in missing packages
butonic Apr 14, 2022
bba190f
add ocis search command
butonic Apr 14, 2022
a0d9946
Fix parsing the search pattern
aduffeck Apr 14, 2022
2de9042
Actually call the search provider when searching
aduffeck Apr 14, 2022
37f64eb
Merge branch 'master' into search
butonic Apr 14, 2022
dcb8e4f
use
butonic Apr 19, 2022
1e5a9e9
Merge branch 'master' into search
butonic Apr 22, 2022
190ee68
Merge branch 'master' into search
butonic Apr 22, 2022
c17717d
enable search in web ui
butonic Apr 22, 2022
5598fc0
Listen to nats and trigger the indexing of uploaded files
aduffeck Apr 21, 2022
3ec212c
Properly pass on the token in the context to the search provider
aduffeck Apr 22, 2022
ca29517
Use proper natsjs plugin
aduffeck Apr 22, 2022
fe61ef5
Fix searching files from the web ui
aduffeck Apr 22, 2022
b14bded
Limit the search to the relevant fields
aduffeck Apr 22, 2022
962840e
Fix file id field in the search response
aduffeck Apr 22, 2022
51cf27d
Add etag, mtime and mimetype to the search index and response
aduffeck Apr 25, 2022
1a84afc
Persist the search index on disk
aduffeck Apr 25, 2022
d5084ee
Add command for (re-)indexing existing spaces
aduffeck Apr 27, 2022
827885a
Add a DocCount() method to the index client
aduffeck Apr 27, 2022
656ef9d
Add a IndexSpace method to the search provider
aduffeck Apr 27, 2022
4dd89aa
Adapt to renamed field
aduffeck Apr 28, 2022
0b0efd6
Remove items from the index when they were deleted
aduffeck Apr 28, 2022
e5338df
Trigger updates on all relevant events
aduffeck Apr 28, 2022
68c5e23
Store the parent id in the index to allow for handling directories
aduffeck Apr 28, 2022
6bd67c0
Mark items as deleted (recursively) but still keep them around
aduffeck Apr 29, 2022
15c60df
Return up to 200 search results
aduffeck Apr 29, 2022
be15d63
Add items back to the index recursively when the parent is restored
aduffeck Apr 29, 2022
18d0fa2
Move the children as well when a directory is moved
aduffeck Apr 29, 2022
08df2e3
Merge remote-tracking branch 'upstream/master' into search
aduffeck Apr 29, 2022
0fdd23c
Fix search config after master merge
aduffeck Apr 29, 2022
851c649
Remove reva go mod replace
aduffeck Apr 29, 2022
498d078
Add changelog
aduffeck Apr 29, 2022
e3b1a0e
Merge remote-tracking branch 'upstream/master' into search
aduffeck Apr 29, 2022
cd285c9
Fix merge error
aduffeck Apr 29, 2022
bfc8196
Merge branch 'master' into search
butonic May 2, 2022
c720d18
update config to init changes
butonic May 2, 2022
4d888cc
fix proxy directorSelectionDirector test
butonic May 2, 2022
acd6b33
expect favorites to fail
butonic May 2, 2022
a1b34a6
Also index new directories
aduffeck May 2, 2022
fd4ec56
Cleanup
aduffeck May 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/search-extension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Add initial version of the search extensions

It is now possible to search for files and directories by their name using the web UI. Therefor new search extension indexes files in a persistent local index.

https://github.com/owncloud/ocis/pull/3635
2 changes: 1 addition & 1 deletion docs/extensions/port-ranges.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ We also suggest to use the last port in your extensions' range as a debug/metric
| 9205-9209 | [markdown-editor](https://github.com/owncloud/ocis-markdown-editor) |
| 9210-9214 | [reva](https://github.com/owncloud/ocis-reva) unused? |
| 9215-9219 | reva metadata storage |
| 9220-9224 | FREE |
| 9220-9224 | search |
| 9225-9229 | photoprism (state: PoC) |
| 9230-9234 | [nats](https://github.com/owncloud/ocis/tree/master/nats) |
| 9235-9239 | idm TBD |
Expand Down
7 changes: 5 additions & 2 deletions docs/extensions/storage/ports.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ For now, the storage service uses these ports to preconfigure those services:
| 9159 | storage users debug |
| 9160 | groups |
| 9161 | groups debug |
| 9164 | storage appprovider |
| 9165 | storage appprovider debug |
| 9164 | storage appprovider |
| 9165 | storage appprovider debug |
| 9178 | storage public link |
| 9179 | storage public link data |
| 9180 | accounts grpc |
| 9181 | accounts http |
| 9182 | accounts debug |
| 9215 | storage meta grpc |
| 9216 | storage meta http |
| 9217 | storage meta debug |
4 changes: 3 additions & 1 deletion extensions/frontend/pkg/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ func frontendConfigFromStruct(c *cli.Context, cfg *config.Config, filesCfg map[s
"preferred_upload_type": cfg.Checksums.PreferredUploadType,
},
"files": filesCfg,
"dav": map[string]interface{}{},
"dav": map[string]interface{}{
"reports": []string{"search-files"},
},
"files_sharing": map[string]interface{}{
"api_enabled": true,
"resharing": false,
Expand Down
6 changes: 4 additions & 2 deletions extensions/proxy/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ type Policy struct {

// Route defines forwarding routes
type Route struct {
Type RouteType `yaml:"type"`
Endpoint string `yaml:"endpoint"`
Type RouteType `yaml:"type"`
// Method optionally limits the route to this HTTP method
Method string `yaml:"method"`
Endpoint string `yaml:"endpoint"`
// Backend is a static URL to forward the request to
Backend string `yaml:"backend"`
// Service name to look up in the registry
Expand Down
9 changes: 9 additions & 0 deletions extensions/proxy/pkg/config/defaults/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ func DefaultPolicies() []config.Policy {
Endpoint: "/remote.php/?preview=1",
Backend: "http://localhost:9115",
},
{
// TODO the actual REPORT goes to /dav/files/{username}, which is user specific ... how would this work in a spaces world?
// TODO what paths are returned? the href contains the full path so it should be possible to return urls from other spaces?
// TODO or we allow a REPORT on /dav/spaces to search all spaces and /dav/space/{spaceid} to search a specific space
// send webdav REPORT requests to search service
Method: "REPORT",
Endpoint: "/remote.php/dav/",
Backend: "http://localhost:9115", // TODO use registry?
},
{
Endpoint: "/remote.php/",
Service: "ocdav",
Expand Down
34 changes: 25 additions & 9 deletions extensions/proxy/pkg/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import (
// MultiHostReverseProxy extends "httputil" to support multiple hosts with different policies
type MultiHostReverseProxy struct {
httputil.ReverseProxy
Directors map[string]map[config.RouteType]map[string]func(req *http.Request)
// Directors holds policy route type method endpoint Director
Directors map[string]map[config.RouteType]map[string]map[string]func(req *http.Request)
PolicySelector policy.Selector
logger log.Logger
config *config.Config
Expand All @@ -40,7 +41,7 @@ func NewMultiHostReverseProxy(opts ...Option) *MultiHostReverseProxy {
options := newOptions(opts...)

rp := &MultiHostReverseProxy{
Directors: make(map[string]map[config.RouteType]map[string]func(req *http.Request)),
Directors: make(map[string]map[config.RouteType]map[string]map[string]func(req *http.Request)),
logger: options.Logger,
config: options.Config,
}
Expand Down Expand Up @@ -124,6 +125,7 @@ func (p *MultiHostReverseProxy) directorSelectionDirector(r *http.Request) {
return
}

method := ""
// find matching director
for _, rt := range config.RouteTypes {
var handler func(string, url.URL) bool
Expand All @@ -137,25 +139,36 @@ func (p *MultiHostReverseProxy) directorSelectionDirector(r *http.Request) {
default:
handler = p.prefixRouteMatcher
}
for endpoint := range p.Directors[pol][rt] {
if p.Directors[pol][rt][r.Method] != nil {
// use specific method
method = r.Method
}
for endpoint := range p.Directors[pol][rt][method] {
if handler(endpoint, *r.URL) {

p.logger.Debug().
Str("policy", pol).
Str("method", r.Method).
Str("prefix", endpoint).
Str("path", r.URL.Path).
Str("routeType", string(rt)).
Msg("director found")

p.Directors[pol][rt][endpoint](r)
p.Directors[pol][rt][method][endpoint](r)
return
}
}
}

// override default director with root. If any
if p.Directors[pol][config.PrefixRoute]["/"] != nil {
p.Directors[pol][config.PrefixRoute]["/"](r)
switch {
case p.Directors[pol][config.PrefixRoute][method]["/"] != nil:
// try specific method
p.Directors[pol][config.PrefixRoute][method]["/"](r)
return
case p.Directors[pol][config.PrefixRoute][""]["/"] != nil:
// fallback to unspecific method
p.Directors[pol][config.PrefixRoute][""]["/"](r)
return
}

Expand All @@ -182,20 +195,23 @@ func singleJoiningSlash(a, b string) string {
func (p *MultiHostReverseProxy) AddHost(policy string, target *url.URL, rt config.Route) {
targetQuery := target.RawQuery
if p.Directors[policy] == nil {
p.Directors[policy] = make(map[config.RouteType]map[string]func(req *http.Request))
p.Directors[policy] = make(map[config.RouteType]map[string]map[string]func(req *http.Request))
}
routeType := config.DefaultRouteType
if rt.Type != "" {
routeType = rt.Type
}
if p.Directors[policy][routeType] == nil {
p.Directors[policy][routeType] = make(map[string]func(req *http.Request))
p.Directors[policy][routeType] = make(map[string]map[string]func(req *http.Request))
}
if p.Directors[policy][routeType][rt.Method] == nil {
p.Directors[policy][routeType][rt.Method] = make(map[string]func(req *http.Request))
}

reg := registry.GetRegistry()
sel := selector.NewSelector(selector.Registry(reg))

p.Directors[policy][routeType][rt.Endpoint] = func(req *http.Request) {
p.Directors[policy][routeType][rt.Method][rt.Endpoint] = func(req *http.Request) {
if rt.Service != "" {
// select next node
next, err := sel.Select(rt.Service)
Expand Down
40 changes: 38 additions & 2 deletions extensions/proxy/pkg/proxy/proxy_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package proxy

import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"

"github.com/owncloud/ocis/extensions/proxy/pkg/config"
"github.com/owncloud/ocis/extensions/proxy/pkg/config/defaults"
)

type matchertest struct {
endpoint, target string
matches bool
method, endpoint, target string
matches bool
}

func TestPrefixRouteMatcher(t *testing.T) {
Expand Down Expand Up @@ -99,3 +103,35 @@ func TestSingleJoiningSlash(t *testing.T) {
}
}
}

func TestDirectorSelectionDirector(t *testing.T) {

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "ok")
}))
defer svr.Close()

p := NewMultiHostReverseProxy(Config(&config.Config{
PolicySelector: &config.PolicySelector{
Static: &config.StaticSelectorConf{
Policy: "default",
},
},
}))
p.AddHost("default", &url.URL{Host: "ocdav"}, config.Route{Type: config.PrefixRoute, Method: "", Endpoint: "/dav", Backend: "ocdav"})
p.AddHost("default", &url.URL{Host: "ocis-webdav"}, config.Route{Type: config.PrefixRoute, Method: "REPORT", Endpoint: "/dav", Backend: "ocis-webdav"})

table := []matchertest{
{method: "PROPFIND", endpoint: "/dav/files/demo/", target: "ocdav"},
{method: "REPORT", endpoint: "/dav/files/demo/", target: "ocis-webdav"},
}

for _, test := range table {
r := httptest.NewRequest(http.MethodGet, "/dav/files/demo/", nil)
p.directorSelectionDirector(r)
if r.Host != test.target {
t.Errorf("TestDirectorSelectionDirector got host %s expected %s", r.Host, test.target)

}
}
}
14 changes: 14 additions & 0 deletions extensions/search/cmd/search/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"os"

"github.com/owncloud/ocis/extensions/search/pkg/command"
"github.com/owncloud/ocis/extensions/search/pkg/config/defaults"
)

func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}
53 changes: 53 additions & 0 deletions extensions/search/pkg/command/health.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package command

import (
"fmt"
"net/http"

"github.com/owncloud/ocis/extensions/search/pkg/config"
"github.com/owncloud/ocis/extensions/search/pkg/config/parser"
"github.com/owncloud/ocis/extensions/search/pkg/logging"
"github.com/urfave/cli/v2"
)

// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)

resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)

if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}

defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}

logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")

return nil
},
}
}
52 changes: 52 additions & 0 deletions extensions/search/pkg/command/index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package command

import (
"context"
"fmt"

"github.com/urfave/cli/v2"

"github.com/owncloud/ocis/extensions/search/pkg/config"
"github.com/owncloud/ocis/extensions/search/pkg/config/parser"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
searchsvc "github.com/owncloud/ocis/protogen/gen/ocis/services/search/v0"
)

// Index is the entrypoint for the server command.
func Index(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "index",
Usage: "index the files for one one more users",
Category: "index management",
Aliases: []string{"i"},
Flags: []cli.Flag{
&cli.StringFlag{
Name: "space",
Aliases: []string{"s"},
Required: true,
Usage: "the id of the space to travers and index the files of",
},
&cli.StringFlag{
Name: "user",
Aliases: []string{"u"},
Required: true,
Usage: "the username of the user tha shall be used to access the files",
},
},
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
client := searchsvc.NewSearchProviderService("com.owncloud.api.search", grpc.DefaultClient)
_, err := client.IndexSpace(context.Background(), &searchsvc.IndexSpaceRequest{
SpaceId: c.String("space"),
UserId: c.String("user"),
})
if err != nil {
fmt.Println("failed to index space: " + err.Error())
return err
}
return nil
},
}
}
Loading