@@ -48,7 +48,9 @@ type MethodSet interface {
4848// Each method is required to have associated attributes in order to successfully register
4949type 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
243251func (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+
431452func (inst * Instance ) buildMethodMap (impl interface {}) map [string ]reflect.Method {
432453 result := make (map [string ]reflect.Method )
433454 implType := reflect .TypeOf (impl )
0 commit comments