Skip to content

Commit e074bf4

Browse files
committed
fix(dispatch): Add default source resolver to Attributes
Attributes has a field for the default source for the method. This lets us remove the WithSource calls throughout the cmd package, and makes tests more readable.
1 parent 5bded08 commit e074bf4

File tree

19 files changed

+211
-81
lines changed

19 files changed

+211
-81
lines changed

cmd/pull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ dataset version(s). By default pull fetches the latest version of a dataset.
3737
}
3838

3939
cmd.Flags().StringVar(&o.LinkDir, "link", "", "path to directory to link dataset to")
40-
cmd.Flags().StringVar(&o.Source, "source", "network", "location to pull from")
40+
cmd.Flags().StringVar(&o.Source, "source", "", "location to pull from")
4141
cmd.MarkFlagFilename("link")
4242
cmd.Flags().BoolVar(&o.LogsOnly, "logs-only", false, "only fetch logs, skipping HEAD data")
4343

cmd/remove.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (o *RemoveOptions) Run() (err error) {
152152
}
153153

154154
ctx := context.TODO()
155-
res, err := o.inst.WithSource("local").Dataset().Remove(ctx, &params)
155+
res, err := o.inst.Dataset().Remove(ctx, &params)
156156
if err != nil {
157157
// TODO(b5): move this error handling down into lib
158158
if errors.Is(err, dsref.ErrRefNotFound) {

cmd/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func (o *ValidateOptions) Run() (err error) {
138138
}
139139

140140
ctx := context.TODO()
141-
res, err := o.inst.WithSource("local").Dataset().Validate(ctx, p)
141+
res, err := o.inst.Dataset().Validate(ctx, p)
142142
if err != nil {
143143
return err
144144
}

lib/access.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (m AccessMethods) Name() string {
2222
// Attributes defines attributes for each method
2323
func (m AccessMethods) Attributes() map[string]AttributeSet {
2424
return map[string]AttributeSet{
25-
"createauthtoken": {AECreateAuthToken, "GET"},
25+
"createauthtoken": {AECreateAuthToken, "GET", "local"},
2626
}
2727
}
2828

lib/automation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (m AutomationMethods) Name() string {
2626
// Attributes defines attributes for each method
2727
func (m AutomationMethods) Attributes() map[string]AttributeSet {
2828
return map[string]AttributeSet{
29-
"apply": {AEApply, "POST"},
29+
"apply": {AEApply, "POST", ""},
3030
}
3131
}
3232

lib/collection.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func (m CollectionMethods) Name() string {
2727
// Attributes defines attributes for each method
2828
func (m CollectionMethods) Attributes() map[string]AttributeSet {
2929
return map[string]AttributeSet{
30-
"list": {AEList, "POST"},
31-
"listrawrefs": {denyRPC, ""},
30+
"list": {AEList, "POST", ""},
31+
"listrawrefs": {denyRPC, "", ""},
3232
}
3333
}
3434

lib/config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ func (m ConfigMethods) Name() string {
2525
func (m ConfigMethods) Attributes() map[string]AttributeSet {
2626
return map[string]AttributeSet{
2727
// config methods are not allowed over HTTP nor RPC
28-
"getconfig": {denyRPC, ""},
29-
"getconfigkeys": {denyRPC, ""},
30-
"setconfig": {denyRPC, ""},
28+
"getconfig": {denyRPC, "", ""},
29+
"getconfigkeys": {denyRPC, "", ""},
30+
"setconfig": {denyRPC, "", ""},
3131
}
3232
}
3333

lib/datasets.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ func (m DatasetMethods) Name() string {
5050
// Attributes defines attributes for each method
5151
func (m DatasetMethods) Attributes() map[string]AttributeSet {
5252
return map[string]AttributeSet{
53-
"componentstatus": {AEComponentStatus, "POST"},
54-
"get": {AEGet, "GET"},
53+
"componentstatus": {AEComponentStatus, "POST", ""},
54+
"get": {AEGet, "GET", ""},
5555
// "log": {AELog, "POST"},
56-
"rename": {AERename, "POST"},
57-
"save": {AESave, "POST"},
58-
"pull": {AEPull, "POST"},
56+
"rename": {AERename, "POST", ""},
57+
"save": {AESave, "POST", ""},
58+
"pull": {AEPull, "POST", "network"},
5959
// "push": {AEPush, "POST"},
60-
"render": {AERender, "POST"},
61-
"remove": {AERemove, "POST"},
62-
"validate": {AEValidate, "POST"},
60+
"render": {AERender, "POST", ""},
61+
"remove": {AERemove, "POST", "local"},
62+
"validate": {AEValidate, "POST", ""},
6363
// "unpack": {AEUnpack, "POST"},
64-
"manifest": {AEManifest, "POST"},
65-
"manifestmissing": {AEManifestMissing, "POST"},
66-
"daginfo": {AEDAGInfo, "POST"},
64+
"manifest": {AEManifest, "POST", ""},
65+
"manifestmissing": {AEManifestMissing, "POST", ""},
66+
"daginfo": {AEDAGInfo, "POST", ""},
6767
}
6868
}
6969

@@ -1311,9 +1311,6 @@ func (datasetImpl) Validate(scope scope, p *ValidateParams) (*ValidateResponse,
13111311
if p.Ref == "" && (p.BodyFilename == "" || schemaFlagType == "") {
13121312
return nil, qrierr.New(ErrBadArgs, "please provide a dataset name, or a supply the --body and --schema or --structure flags")
13131313
}
1314-
if scope.SourceName() != "local" {
1315-
return nil, fmt.Errorf("validate requires 'local' source")
1316-
}
13171314

13181315
fsiPath := ""
13191316
var err error

lib/diff.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ func (m DiffMethods) Name() string {
2626
// Attributes defines attributes for each method
2727
func (m DiffMethods) Attributes() map[string]AttributeSet {
2828
return map[string]AttributeSet{
29-
"changes": {AEChanges, "POST"},
30-
"diff": {AEDiff, "POST"},
29+
"changes": {AEChanges, "POST", ""},
30+
"diff": {AEDiff, "POST", ""},
3131
}
3232
}
3333

lib/dispatch.go

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ type MethodSet interface {
4848
// Each method is required to have associated attributes in order to successfully register
4949
type AttributeSet struct {
5050
endpoint APIEndpoint
51-
verb string
51+
httpVerb string
52+
// the default source used for resolving references
53+
defaultSource string
5254
}
5355

5456
// Dispatch is a system for handling calls to lib. Should only be called by top-level lib methods.
@@ -144,6 +146,11 @@ func (inst *Instance) dispatchMethodCall(ctx context.Context, method string, par
144146

145147
// Look up the method for the given signifier
146148
if c, ok := inst.regMethods.lookup(method); ok {
149+
// If this method has a default source and no override exists, use that
150+
// default instead
151+
if source == "" {
152+
source = c.Source
153+
}
147154
// Construct the isolated scope for this call
148155
// TODO(dustmop): Add user authentication, profile, identity, etc
149156
// TODO(dustmop): Also determine if the method is read-only vs read-write,
@@ -237,12 +244,14 @@ type callable struct {
237244
RetCursor bool
238245
Endpoint APIEndpoint
239246
Verb string
247+
Source string
240248
}
241249

242250
// RegisterMethods iterates the methods provided by the lib API, and makes them visible to dispatch
243251
func (inst *Instance) RegisterMethods() {
244252
reg := make(map[string]callable)
245253
inst.registerOne("access", inst.Access(), accessImpl{}, reg)
254+
inst.registerOne("automation", inst.Automation(), automationImpl{}, reg)
246255
inst.registerOne("collection", inst.Collection(), collectionImpl{}, reg)
247256
inst.registerOne("config", inst.Config(), configImpl{}, reg)
248257
inst.registerOne("dataset", inst.Dataset(), datasetImpl{}, reg)
@@ -255,7 +264,6 @@ func (inst *Instance) RegisterMethods() {
255264
inst.registerOne("remote", inst.Remote(), remoteImpl{}, reg)
256265
inst.registerOne("search", inst.Search(), searchImpl{}, reg)
257266
inst.registerOne("sql", inst.SQL(), sqlImpl{}, reg)
258-
inst.registerOne("automation", inst.Automation(), automationImpl{}, reg)
259267
inst.regMethods = &regMethodSet{reg: reg}
260268
}
261269

@@ -384,25 +392,13 @@ func (inst *Instance) registerOne(ourName string, methods MethodSet, impl interf
384392
// Remove this method from the methodSetMap now that it has been processed
385393
delete(methodMap, i.Name)
386394

387-
var endpoint APIEndpoint
388-
var httpVerb string
389395
// Additional attributes for the method are found in the Attributes
390396
amap := methods.Attributes()
391397
methodAttrs, ok := amap[lowerName]
392398
if !ok {
393399
regFail("not in Attributes: %s.%s", ourName, lowerName)
394400
}
395-
endpoint = methodAttrs.endpoint
396-
httpVerb = methodAttrs.verb
397-
// If both these are empty string, RPC is not allowed for this method
398-
if endpoint != "" || httpVerb != "" {
399-
if !strings.HasPrefix(string(endpoint), "/") {
400-
regFail("%s: endpoint URL must start with /, got %q", lowerName, endpoint)
401-
}
402-
if httpVerb != http.MethodGet && httpVerb != http.MethodPost && httpVerb != http.MethodPut {
403-
regFail("%s: unknown http verb, got %q", lowerName, httpVerb)
404-
}
405-
}
401+
validateMethodAttrs(lowerName, methodAttrs)
406402

407403
// Save the method to the registration table
408404
reg[funcName] = callable{
@@ -411,8 +407,9 @@ func (inst *Instance) registerOne(ourName string, methods MethodSet, impl interf
411407
InType: inType,
412408
OutType: outType,
413409
RetCursor: returnsCursor,
414-
Endpoint: endpoint,
415-
Verb: httpVerb,
410+
Endpoint: methodAttrs.endpoint,
411+
Verb: methodAttrs.httpVerb,
412+
Source: methodAttrs.defaultSource,
416413
}
417414
log.Debugf("%d: registered %s(*%s) %v", k, funcName, inType, outType)
418415
}
@@ -428,6 +425,30 @@ func regFail(fstr string, vals ...interface{}) {
428425
panic(fmt.Sprintf(fstr, vals...))
429426
}
430427

428+
func validateMethodAttrs(methodName string, attrs AttributeSet) {
429+
// If endpoint and verb are not set, then RPC is denied, nothing to validate
430+
// TODO(dustmop): Technically this is denying all HTTP, not just RPC. Consider
431+
// separating HTTP and RPC denial
432+
if attrs.endpoint == "" && attrs.httpVerb == "" {
433+
return
434+
}
435+
if !strings.HasPrefix(string(attrs.endpoint), "/") {
436+
regFail("%s: endpoint URL must start with /, got %q", methodName, attrs.endpoint)
437+
}
438+
if !stringOneOf(attrs.httpVerb, []string{http.MethodGet, http.MethodPost, http.MethodPut}) {
439+
regFail("%s: unknown http verb, got %q", methodName, attrs.httpVerb)
440+
}
441+
}
442+
443+
func stringOneOf(needle string, haystack []string) bool {
444+
for _, each := range haystack {
445+
if needle == each {
446+
return true
447+
}
448+
}
449+
return false
450+
}
451+
431452
func (inst *Instance) buildMethodMap(impl interface{}) map[string]reflect.Method {
432453
result := make(map[string]reflect.Method)
433454
implType := reflect.TypeOf(impl)

0 commit comments

Comments
 (0)