blob: 7f2fd1f4bcde1739df4207a1c3c1b1e2fbd5aa81 [file] [log] [blame]
Adam Sadovskyb85e3532015-04-08 20:38:27 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Adam Sadovskyb85e3532015-04-08 20:38:27 -07005package server
6
7import (
8 "strings"
9
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070010 wire "v.io/syncbase/v23/services/syncbase"
Adam Sadovsky49261192015-05-19 17:39:59 -070011 pubutil "v.io/syncbase/v23/syncbase/util"
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070012 "v.io/syncbase/x/ref/services/syncbase/server/nosql"
Himabindu Puchafb26a832015-05-20 15:37:50 -070013 "v.io/syncbase/x/ref/services/syncbase/server/util"
Adam Sadovskyb85e3532015-04-08 20:38:27 -070014 "v.io/v23/rpc"
15 "v.io/v23/security"
16 "v.io/v23/verror"
17)
18
19type dispatcher struct {
20 s *service
21}
22
23var _ rpc.Dispatcher = (*dispatcher)(nil)
24
25func NewDispatcher(s *service) *dispatcher {
26 return &dispatcher{s: s}
27}
28
29// TODO(sadovsky): Return a real authorizer in various places below.
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070030func (disp *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
Adam Sadovskyb85e3532015-04-08 20:38:27 -070031 suffix = strings.TrimPrefix(suffix, "/")
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070032 parts := strings.SplitN(suffix, "/", 2)
33
34 if len(suffix) == 0 {
35 return wire.ServiceServer(disp.s), nil, nil
36 }
Adam Sadovskyb85e3532015-04-08 20:38:27 -070037
Himabindu Puchafb26a832015-05-20 15:37:50 -070038 if parts[0] == util.SyncbaseSuffix {
39 return disp.s.sync, nil, nil
40 }
41
Adam Sadovskyb85e3532015-04-08 20:38:27 -070042 // Validate all key atoms up front, so that we can avoid doing so in all our
43 // method implementations.
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070044 appName := parts[0]
Adam Sadovsky49261192015-05-19 17:39:59 -070045 if !pubutil.ValidName(appName) {
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070046 return nil, nil, wire.NewErrInvalidName(nil, suffix)
47 }
48
49 aExists := false
Adam Sadovskybc00bd62015-05-22 12:50:03 -070050 var a *app
51 if aint, err := disp.s.App(nil, nil, appName); err == nil {
52 a = aint.(*app) // panics on failure, as desired
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070053 aExists = true
54 } else {
55 if verror.ErrorID(err) != verror.ErrNoExistOrNoAccess.ID {
56 return nil, nil, err
57 } else {
58 a = &app{
59 name: appName,
60 s: disp.s,
61 }
Adam Sadovskyb85e3532015-04-08 20:38:27 -070062 }
63 }
64
Adam Sadovskyb85e3532015-04-08 20:38:27 -070065 if len(parts) == 1 {
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070066 return wire.AppServer(a), nil, nil
Adam Sadovskyb85e3532015-04-08 20:38:27 -070067 }
68
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070069 // All database, table, and row methods require the app to exist. If it
70 // doesn't, abort early.
71 if !aExists {
72 return nil, nil, verror.New(verror.ErrNoExistOrNoAccess, nil, a.name)
Adam Sadovskyb85e3532015-04-08 20:38:27 -070073 }
74
Adam Sadovskyf3b7abc2015-05-04 15:33:22 -070075 // Note, it's possible for the app to be deleted concurrently with downstream
76 // handling of this request. Depending on the order in which things execute,
77 // the client may not get an error, but in any case ultimately the store will
78 // end up in a consistent state.
79 return nosql.NewDispatcher(a).Lookup(parts[1])
Adam Sadovskyb85e3532015-04-08 20:38:27 -070080}