| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package nosql |
| |
| import ( |
| "strings" |
| |
| wire "v.io/syncbase/v23/services/syncbase" |
| nosqlWire "v.io/syncbase/v23/services/syncbase/nosql" |
| pubutil "v.io/syncbase/v23/syncbase/util" |
| "v.io/syncbase/x/ref/services/syncbase/server/interfaces" |
| "v.io/v23/rpc" |
| "v.io/v23/security" |
| "v.io/v23/verror" |
| "v.io/x/lib/vlog" |
| ) |
| |
| type dispatcher struct { |
| a interfaces.App |
| } |
| |
| var _ rpc.Dispatcher = (*dispatcher)(nil) |
| |
| func NewDispatcher(a interfaces.App) *dispatcher { |
| return &dispatcher{a: a} |
| } |
| |
| func (disp *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) { |
| suffix = strings.TrimPrefix(suffix, "/") |
| parts := strings.Split(suffix, "/") |
| |
| if len(parts) == 0 { |
| vlog.Fatal("invalid nosql.dispatcher Lookup") |
| } |
| |
| // Validate all key atoms up front, so that we can avoid doing so in all our |
| // method implementations. |
| for _, s := range parts { |
| if !pubutil.ValidName(s) { |
| return nil, nil, wire.NewErrInvalidName(nil, suffix) |
| } |
| } |
| |
| dExists := false |
| var d *database |
| if dint, err := disp.a.NoSQLDatabase(nil, nil, parts[0]); err == nil { |
| d = dint.(*database) // panics on failure, as desired |
| dExists = true |
| } else { |
| if verror.ErrorID(err) != verror.ErrNoExist.ID { |
| return nil, nil, err |
| } else { |
| d = &database{ |
| name: parts[0], |
| a: disp.a, |
| } |
| } |
| } |
| |
| if len(parts) == 1 { |
| return nosqlWire.DatabaseServer(d), nil, nil |
| } |
| |
| // All table and row methods require the database to exist. If it doesn't, |
| // abort early. |
| if !dExists { |
| return nil, nil, verror.New(verror.ErrNoExist, nil, d.name) |
| } |
| |
| // Note, it's possible for the database to be deleted concurrently with |
| // downstream handling of this request. Depending on the order in which things |
| // execute, the client may not get an error, but in any case ultimately the |
| // store will end up in a consistent state. |
| t := &table{ |
| name: parts[1], |
| d: d, |
| } |
| if len(parts) == 2 { |
| return nosqlWire.TableServer(t), nil, nil |
| } |
| |
| r := &row{ |
| key: parts[2], |
| t: t, |
| } |
| if len(parts) == 3 { |
| return nosqlWire.RowServer(r), nil, nil |
| } |
| |
| return nil, nil, verror.NewErrNoExist(nil) |
| } |