blob: 09d1b70f99f0661056e2575cbfff40ace0f84937 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -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
Matt Rosencrantz5845bf12015-01-06 13:05:21 -08005package rt
6
7import (
8 "fmt"
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -08009 "os"
10 "os/signal"
11 "path/filepath"
12 "strings"
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -080013 "syscall"
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080014 "time"
15
Cosmos Nicolaou9691e5d2015-06-17 12:24:35 -070016 "v.io/x/lib/metadata"
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070017 "v.io/x/lib/pubsub"
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -070018 "v.io/x/lib/vlog"
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070019
Jiri Simsa6ac95222015-02-23 16:11:49 -080020 "v.io/v23"
21 "v.io/v23/context"
22 "v.io/v23/i18n"
Todd Wang5082a552015-04-02 10:56:11 -070023 "v.io/v23/namespace"
Jiri Simsa6ac95222015-02-23 16:11:49 -080024 "v.io/v23/naming"
25 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070026 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080027 "v.io/v23/security"
28 "v.io/v23/verror"
Jiri Simsa6ac95222015-02-23 16:11:49 -080029 "v.io/v23/vtrace"
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -070030
31 "v.io/x/ref/internal/logger"
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -070032 "v.io/x/ref/lib/apilog"
Jiri Simsaffceefa2015-02-28 11:03:34 -080033 "v.io/x/ref/lib/flags"
Jiri Simsaffceefa2015-02-28 11:03:34 -080034 "v.io/x/ref/lib/stats"
35 _ "v.io/x/ref/lib/stats/sysstats"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070036 "v.io/x/ref/runtime/internal/lib/dependency"
37 inaming "v.io/x/ref/runtime/internal/naming"
38 inamespace "v.io/x/ref/runtime/internal/naming/namespace"
39 irpc "v.io/x/ref/runtime/internal/rpc"
40 "v.io/x/ref/runtime/internal/rpc/stream"
41 imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
42 ivtrace "v.io/x/ref/runtime/internal/vtrace"
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080043)
44
45type contextKey int
46
47const (
48 streamManagerKey = contextKey(iota)
49 clientKey
50 namespaceKey
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080051 principalKey
Matt Rosencrantz3838c552015-01-15 13:04:53 -080052 backgroundKey
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070053 reservedNameKey
54
55 // initKey is used to store values that are only set at init time.
56 initKey
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080057)
58
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070059type initData struct {
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070060 appCycle v23.AppCycle
61 listenSpec *rpc.ListenSpec
62 protocols []string
63 settingsPublisher *pubsub.Publisher
64 settingsName string
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070065}
66
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080067type vtraceDependency struct{}
68
Jiri Simsa6ac95222015-02-23 16:11:49 -080069// Runtime implements the v23.Runtime interface.
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080070// Please see the interface definition for documentation of the
71// individiual methods.
Matt Rosencrantzba470a52015-01-26 13:36:13 -080072type Runtime struct {
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -080073 deps *dependency.Graph
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -080074}
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080075
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070076func Init(
77 ctx *context.T,
78 appCycle v23.AppCycle,
79 protocols []string,
80 listenSpec *rpc.ListenSpec,
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070081 settingsPublisher *pubsub.Publisher,
82 settingsName string,
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070083 flags flags.RuntimeFlags,
84 reservedDispatcher rpc.Dispatcher) (*Runtime, *context.T, v23.Shutdown, error) {
Matt Rosencrantzba470a52015-01-26 13:36:13 -080085 r := &Runtime{deps: dependency.NewGraph()}
Matt Rosencrantz96d952a2015-01-15 09:18:38 -080086
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070087 ctx = context.WithValue(ctx, initKey, &initData{
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070088 protocols: protocols,
89 listenSpec: listenSpec,
90 appCycle: appCycle,
91 settingsPublisher: settingsPublisher,
92 settingsName: settingsName,
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070093 })
94
95 if reservedDispatcher != nil {
96 ctx = context.WithValue(ctx, reservedNameKey, reservedDispatcher)
97 }
98
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -070099 err := logger.Manager(logger.Global()).ConfigureFromFlags()
Cosmos Nicolaou92c57482015-05-22 13:29:15 -0700100 if err != nil && err != vlog.ErrConfigured {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800101 return nil, nil, nil, err
102 }
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700103
104 // Configure the context to use the global logger.
105 ctx = context.WithLogger(ctx, logger.Global())
106
Todd Wang3f7ceb42015-05-04 17:51:34 -0700107 // We want to print out metadata only into the log files, to avoid
Bogdan Caprita3eb74692015-03-05 09:34:18 -0800108 // spamming stderr, see #1246.
109 //
110 // TODO(caprita): We should add it to the log file header information;
111 // since that requires changes to the llog and vlog packages, for now we
Todd Wang3f7ceb42015-05-04 17:51:34 -0700112 // condition printing of metadata on having specified an explicit
113 // log_dir for the program. It's a hack, but it gets us the metadata
114 // to device manager-run apps and avoids it for command-lines, which is
Bogdan Caprita3eb74692015-03-05 09:34:18 -0800115 // a good enough approximation.
Cosmos Nicolaou9691e5d2015-06-17 12:24:35 -0700116 if logger.Manager(ctx).LogDir() != os.TempDir() {
117 ctx.Infof(metadata.ToXML())
118 }
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800119
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800120 // Setup the initial trace.
121 ctx, err = ivtrace.Init(ctx, flags.Vtrace)
122 if err != nil {
123 return nil, nil, nil, err
124 }
Todd Wangad492042015-04-17 15:58:40 -0700125 ctx, _ = vtrace.WithNewTrace(ctx)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800126 r.addChild(ctx, vtraceDependency{}, func() {
127 vtrace.FormatTraces(os.Stderr, vtrace.GetStore(ctx).TraceRecords(), nil)
128 })
129
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800130 // Setup i18n.
Todd Wangad492042015-04-17 15:58:40 -0700131 ctx = i18n.WithLangID(ctx, i18n.LangIDFromEnv())
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800132 if len(flags.I18nCatalogue) != 0 {
133 cat := i18n.Cat()
134 for _, filename := range strings.Split(flags.I18nCatalogue, ",") {
135 err := cat.MergeFromFile(filename)
136 if err != nil {
137 fmt.Fprintf(os.Stderr, "%s: i18n: error reading i18n catalogue file %q: %s\n", os.Args[0], filename, err)
138 }
139 }
140 }
141
142 // Setup the program name.
Todd Wangad492042015-04-17 15:58:40 -0700143 ctx = verror.WithComponentName(ctx, filepath.Base(os.Args[0]))
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800144
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800145 // Enable signal handling.
146 r.initSignalHandling(ctx)
147
148 // Set the initial namespace.
149 ctx, _, err = r.setNewNamespace(ctx, flags.NamespaceRoots...)
150 if err != nil {
151 return nil, nil, nil, err
152 }
153
Asim Shankare89936f2015-04-22 17:37:43 -0700154 // Create and set the principal
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700155 principal, deps, shutdown, err := r.initPrincipal(ctx, flags.Credentials)
Asim Shankare89936f2015-04-22 17:37:43 -0700156 if err != nil {
157 return nil, nil, nil, err
158 }
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700159 ctx, err = r.setPrincipal(ctx, principal, shutdown, deps...)
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800160 if err != nil {
161 return nil, nil, nil, err
162 }
163
Asim Shankare89936f2015-04-22 17:37:43 -0700164 // Setup authenticated "networking"
165 ctx, err = r.WithNewStreamManager(ctx)
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800166 if err != nil {
167 return nil, nil, nil, err
168 }
169
Asim Shankare89936f2015-04-22 17:37:43 -0700170 return r, r.WithBackgroundContext(ctx), r.shutdown, nil
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800171}
172
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800173func (r *Runtime) addChild(ctx *context.T, me interface{}, stop func(), dependsOn ...interface{}) error {
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800174 if err := r.deps.Depend(me, dependsOn...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800175 stop()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800176 return err
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800177 } else if done := ctx.Done(); done != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800178 go func() {
179 <-done
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800180 finish := r.deps.CloseAndWait(me)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800181 stop()
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800182 finish()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800183 }()
184 }
185 return nil
186}
187
Matt Rosencrantz31995882015-01-27 20:00:48 -0800188func (r *Runtime) Init(ctx *context.T) error {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700189 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz31995882015-01-27 20:00:48 -0800190 return r.initMgmt(ctx)
191}
192
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800193func (r *Runtime) shutdown() {
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800194 r.deps.CloseAndWaitForAll()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800195 vlog.FlushLog()
196}
197
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800198func (r *Runtime) initSignalHandling(ctx *context.T) {
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800199 // TODO(caprita): Given that our device manager implementation is to
200 // kill all child apps when the device manager dies, we should
201 // enable SIGHUP on apps by default.
202
203 // Automatically handle SIGHUP to prevent applications started as
204 // daemons from being killed. The developer can choose to still listen
205 // on SIGHUP and take a different action if desired.
Matt Rosencrantzcf714c62015-01-22 16:15:56 -0800206 signals := make(chan os.Signal, 1)
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800207 signal.Notify(signals, syscall.SIGHUP)
208 go func() {
209 for {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800210 sig, ok := <-signals
211 if !ok {
212 break
213 }
214 vlog.Infof("Received signal %v", sig)
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800215 }
216 }()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800217 r.addChild(ctx, signals, func() {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800218 signal.Stop(signals)
219 close(signals)
220 })
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800221}
222
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800223func (*Runtime) NewEndpoint(ep string) (naming.Endpoint, error) {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700224 // nologcall
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800225 return inaming.NewEndpoint(ep)
226}
227
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700228func (r *Runtime) NewServer(ctx *context.T, opts ...rpc.ServerOpt) (rpc.Server, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700229 defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800230 // Create a new RoutingID (and StreamManager) for each server.
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800231 sm, err := newStreamManager()
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800232 if err != nil {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700233 return nil, fmt.Errorf("failed to create rpc/stream/Manager: %v", err)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800234 }
235
Todd Wang5082a552015-04-02 10:56:11 -0700236 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800237 principal, _ := ctx.Value(principalKey).(security.Principal)
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700238 client, _ := ctx.Value(clientKey).(rpc.Client)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800239
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700240 otherOpts := append([]rpc.ServerOpt{}, opts...)
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700241
242 if reservedDispatcher := r.GetReservedNameDispatcher(ctx); reservedDispatcher != nil {
243 otherOpts = append(otherOpts, irpc.ReservedNameDispatcher{
244 Dispatcher: reservedDispatcher,
245 })
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800246 }
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800247
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700248 id, _ := ctx.Value(initKey).(*initData)
249 if id.protocols != nil {
250 otherOpts = append(otherOpts, irpc.PreferredServerResolveProtocols(id.protocols))
251 }
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800252 if !hasServerBlessingsOpt(opts) && principal != nil {
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700253 otherOpts = append(otherOpts, options.ServerBlessings{
254 Blessings: principal.BlessingStore().Default(),
255 })
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800256 }
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -0700257 server, err := irpc.InternalNewServer(ctx, sm, ns, id.settingsPublisher, id.settingsName, r.GetClient(ctx), principal, otherOpts...)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800258 if err != nil {
259 return nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800260 }
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800261 stop := func() {
262 if err := server.Stop(); err != nil {
263 vlog.Errorf("A server could not be stopped: %v", err)
264 }
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800265 sm.Shutdown()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800266 }
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700267 deps := []interface{}{client, vtraceDependency{}}
268 if principal != nil {
269 deps = append(deps, principal)
270 }
271 if err = r.addChild(ctx, server, stop, deps...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800272 return nil, err
273 }
274 return server, nil
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800275}
276
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700277func hasServerBlessingsOpt(opts []rpc.ServerOpt) bool {
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800278 for _, o := range opts {
279 if _, ok := o.(options.ServerBlessings); ok {
280 return true
281 }
282 }
283 return false
284}
285
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800286func newStreamManager() (stream.Manager, error) {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800287 rid, err := naming.NewRoutingID()
288 if err != nil {
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800289 return nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800290 }
291 sm := imanager.InternalNew(rid)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800292 return sm, nil
293}
294
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800295func (r *Runtime) setNewStreamManager(ctx *context.T) (*context.T, error) {
296 sm, err := newStreamManager()
297 if err != nil {
298 return nil, err
299 }
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800300 newctx := context.WithValue(ctx, streamManagerKey, sm)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800301 if err = r.addChild(ctx, sm, sm.Shutdown); err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800302 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800303 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800304 return newctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800305}
306
Todd Wangad492042015-04-17 15:58:40 -0700307func (r *Runtime) WithNewStreamManager(ctx *context.T) (*context.T, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700308 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800309 newctx, err := r.setNewStreamManager(ctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800310 if err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800311 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800312 }
313
314 // Create a new client since it depends on the stream manager.
Todd Wangad492042015-04-17 15:58:40 -0700315 newctx, _, err = r.WithNewClient(newctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800316 if err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800317 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800318 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800319 return newctx, nil
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800320}
321
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700322func (r *Runtime) setPrincipal(ctx *context.T, principal security.Principal, shutdown func(), deps ...interface{}) (*context.T, error) {
Suharsh Sivakumar2c5d8102015-03-23 08:49:12 -0700323 if principal != nil {
324 // We uniquely identify a principal with "security/principal/<publicKey>"
325 principalName := "security/principal/" + principal.PublicKey().String()
326 stats.NewStringFunc(principalName+"/blessingstore", principal.BlessingStore().DebugString)
327 stats.NewStringFunc(principalName+"/blessingroots", principal.Roots().DebugString)
328 }
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700329 ctx = context.WithValue(ctx, principalKey, principal)
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700330 return ctx, r.addChild(ctx, principal, shutdown, deps...)
Suharsh Sivakumar5ca46642015-01-30 10:33:38 -0800331}
332
Todd Wangad492042015-04-17 15:58:40 -0700333func (r *Runtime) WithPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700334 defer apilog.LogCallf(ctx, "principal=")(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800335 var err error
336 newctx := ctx
337
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700338 // TODO(mattr, suharshs): If there user gives us some principal that has dependencies
339 // we don't know about, we will not honour those dependencies during shutdown.
340 // For example if they create an agent principal with some client, we don't know
341 // about that, so servers based of this new principal will not prevent the client
342 // from terminating early.
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700343 if newctx, err = r.setPrincipal(ctx, principal, func() {}); err != nil {
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700344 return ctx, err
345 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800346 if newctx, err = r.setNewStreamManager(newctx); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800347 return ctx, err
348 }
Suharsh Sivakumar033a30e2015-01-07 13:54:43 -0800349 if newctx, _, err = r.setNewNamespace(newctx, r.GetNamespace(ctx).Roots()...); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800350 return ctx, err
351 }
Todd Wangad492042015-04-17 15:58:40 -0700352 if newctx, _, err = r.WithNewClient(newctx); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800353 return ctx, err
354 }
355
356 return newctx, nil
357}
358
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800359func (*Runtime) GetPrincipal(ctx *context.T) security.Principal {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700360 // nologcall
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800361 p, _ := ctx.Value(principalKey).(security.Principal)
362 return p
363}
364
Todd Wangad492042015-04-17 15:58:40 -0700365func (r *Runtime) WithNewClient(ctx *context.T, opts ...rpc.ClientOpt) (*context.T, rpc.Client, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700366 defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700367 otherOpts := append([]rpc.ClientOpt{}, opts...)
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800368
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700369 p, _ := ctx.Value(principalKey).(security.Principal)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800370 sm, _ := ctx.Value(streamManagerKey).(stream.Manager)
Todd Wang5082a552015-04-02 10:56:11 -0700371 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700372 otherOpts = append(otherOpts, imanager.DialTimeout(5*time.Minute))
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800373
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700374 if id, _ := ctx.Value(initKey).(*initData); id.protocols != nil {
375 otherOpts = append(otherOpts, irpc.PreferredProtocols(id.protocols))
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800376 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700377 client, err := irpc.InternalNewClient(sm, ns, otherOpts...)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800378 if err != nil {
379 return ctx, nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800380 }
Matt Rosencrantz19329122015-01-23 22:18:49 -0800381 newctx := context.WithValue(ctx, clientKey, client)
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700382 deps := []interface{}{sm, vtraceDependency{}}
383 if p != nil {
384 deps = append(deps, p)
385 }
386 if err = r.addChild(ctx, client, client.Close, deps...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800387 return ctx, nil, err
388 }
389 return newctx, client, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800390}
391
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700392func (*Runtime) GetClient(ctx *context.T) rpc.Client {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700393 // nologcall
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700394 cl, _ := ctx.Value(clientKey).(rpc.Client)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800395 return cl
396}
397
Todd Wang5082a552015-04-02 10:56:11 -0700398func (r *Runtime) setNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) {
399 ns, err := inamespace.New(roots...)
Asim Shankar263c73b2015-03-19 18:31:26 -0700400 if err != nil {
401 return nil, nil, err
402 }
Matt Rosencrantz001644e2015-01-29 14:24:48 -0800403
404 if oldNS := r.GetNamespace(ctx); oldNS != nil {
405 ns.CacheCtl(oldNS.CacheCtl()...)
406 }
407
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800408 if err == nil {
409 ctx = context.WithValue(ctx, namespaceKey, ns)
410 }
411 return ctx, ns, err
412}
413
Todd Wangad492042015-04-17 15:58:40 -0700414func (r *Runtime) WithNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700415 defer apilog.LogCallf(ctx, "roots...=%v", roots)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800416 newctx, ns, err := r.setNewNamespace(ctx, roots...)
417 if err != nil {
418 return ctx, nil, err
419 }
420
421 // Replace the client since it depends on the namespace.
Todd Wangad492042015-04-17 15:58:40 -0700422 newctx, _, err = r.WithNewClient(newctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800423 if err != nil {
424 return ctx, nil, err
425 }
426
427 return newctx, ns, err
428}
429
Todd Wang5082a552015-04-02 10:56:11 -0700430func (*Runtime) GetNamespace(ctx *context.T) namespace.T {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700431 // nologcall
Todd Wang5082a552015-04-02 10:56:11 -0700432 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800433 return ns
434}
435
Jiri Simsa6ac95222015-02-23 16:11:49 -0800436func (*Runtime) GetAppCycle(ctx *context.T) v23.AppCycle {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700437 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700438 id, _ := ctx.Value(initKey).(*initData)
439 return id.appCycle
Suharsh Sivakumar033a30e2015-01-07 13:54:43 -0800440}
441
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700442func (*Runtime) GetListenSpec(ctx *context.T) rpc.ListenSpec {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700443 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700444 if id, _ := ctx.Value(initKey).(*initData); id.listenSpec != nil {
445 return id.listenSpec.Copy()
446 }
447 return rpc.ListenSpec{}
Suharsh Sivakumarac9feed2015-01-08 10:58:37 -0800448}
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800449
Todd Wangad492042015-04-17 15:58:40 -0700450func (*Runtime) WithBackgroundContext(ctx *context.T) *context.T {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700451 // nologcall
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800452 // Note we add an extra context with a nil value here.
453 // This prevents users from travelling back through the
454 // chain of background contexts.
455 ctx = context.WithValue(ctx, backgroundKey, nil)
456 return context.WithValue(ctx, backgroundKey, ctx)
457}
458
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800459func (*Runtime) GetBackgroundContext(ctx *context.T) *context.T {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700460 // nologcall
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800461 bctx, _ := ctx.Value(backgroundKey).(*context.T)
462 if bctx == nil {
463 // There should always be a background context. If we don't find
464 // it, that means that the user passed us the background context
465 // in hopes of following the chain. Instead we just give them
466 // back what they sent in, which is correct.
467 return ctx
468 }
469 return bctx
470}
Robert Kroeger316442c2015-03-26 13:56:11 -0700471
Todd Wangad492042015-04-17 15:58:40 -0700472func (*Runtime) WithReservedNameDispatcher(ctx *context.T, d rpc.Dispatcher) *context.T {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700473 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700474 return context.WithValue(ctx, reservedNameKey, d)
Robert Kroeger316442c2015-03-26 13:56:11 -0700475}
476
477func (*Runtime) GetReservedNameDispatcher(ctx *context.T) rpc.Dispatcher {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700478 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700479 if d, ok := ctx.Value(reservedNameKey).(rpc.Dispatcher); ok {
480 return d
Robert Kroeger316442c2015-03-26 13:56:11 -0700481 }
482 return nil
483}