blob: e3d8a1b737fa449c9a7fc2076002f02485cb9e3a [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
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070054 listenKey
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070055
56 // initKey is used to store values that are only set at init time.
57 initKey
Matt Rosencrantz5845bf12015-01-06 13:05:21 -080058)
59
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070060type initData struct {
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070061 appCycle v23.AppCycle
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070062 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,
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -070089 appCycle: appCycle,
90 settingsPublisher: settingsPublisher,
91 settingsName: settingsName,
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070092 })
93
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070094 if listenSpec != nil {
95 ctx = context.WithValue(ctx, listenKey, listenSpec.Copy())
96 }
97
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -070098 if reservedDispatcher != nil {
99 ctx = context.WithValue(ctx, reservedNameKey, reservedDispatcher)
100 }
101
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700102 err := logger.Manager(logger.Global()).ConfigureFromFlags()
Cosmos Nicolaou92c57482015-05-22 13:29:15 -0700103 if err != nil && err != vlog.ErrConfigured {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800104 return nil, nil, nil, err
105 }
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700106
107 // Configure the context to use the global logger.
108 ctx = context.WithLogger(ctx, logger.Global())
109
Todd Wang3f7ceb42015-05-04 17:51:34 -0700110 // We want to print out metadata only into the log files, to avoid
Bogdan Caprita3eb74692015-03-05 09:34:18 -0800111 // spamming stderr, see #1246.
112 //
113 // TODO(caprita): We should add it to the log file header information;
114 // since that requires changes to the llog and vlog packages, for now we
Todd Wang3f7ceb42015-05-04 17:51:34 -0700115 // condition printing of metadata on having specified an explicit
116 // log_dir for the program. It's a hack, but it gets us the metadata
117 // to device manager-run apps and avoids it for command-lines, which is
Bogdan Caprita3eb74692015-03-05 09:34:18 -0800118 // a good enough approximation.
Cosmos Nicolaou9691e5d2015-06-17 12:24:35 -0700119 if logger.Manager(ctx).LogDir() != os.TempDir() {
120 ctx.Infof(metadata.ToXML())
121 }
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800122
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800123 // Setup the initial trace.
124 ctx, err = ivtrace.Init(ctx, flags.Vtrace)
125 if err != nil {
126 return nil, nil, nil, err
127 }
Todd Wangad492042015-04-17 15:58:40 -0700128 ctx, _ = vtrace.WithNewTrace(ctx)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800129 r.addChild(ctx, vtraceDependency{}, func() {
130 vtrace.FormatTraces(os.Stderr, vtrace.GetStore(ctx).TraceRecords(), nil)
131 })
132
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800133 // Setup i18n.
Todd Wangad492042015-04-17 15:58:40 -0700134 ctx = i18n.WithLangID(ctx, i18n.LangIDFromEnv())
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800135 if len(flags.I18nCatalogue) != 0 {
136 cat := i18n.Cat()
137 for _, filename := range strings.Split(flags.I18nCatalogue, ",") {
138 err := cat.MergeFromFile(filename)
139 if err != nil {
140 fmt.Fprintf(os.Stderr, "%s: i18n: error reading i18n catalogue file %q: %s\n", os.Args[0], filename, err)
141 }
142 }
143 }
144
145 // Setup the program name.
Todd Wangad492042015-04-17 15:58:40 -0700146 ctx = verror.WithComponentName(ctx, filepath.Base(os.Args[0]))
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800147
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800148 // Enable signal handling.
149 r.initSignalHandling(ctx)
150
151 // Set the initial namespace.
152 ctx, _, err = r.setNewNamespace(ctx, flags.NamespaceRoots...)
153 if err != nil {
154 return nil, nil, nil, err
155 }
156
Asim Shankare89936f2015-04-22 17:37:43 -0700157 // Create and set the principal
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700158 principal, deps, shutdown, err := r.initPrincipal(ctx, flags.Credentials)
Asim Shankare89936f2015-04-22 17:37:43 -0700159 if err != nil {
160 return nil, nil, nil, err
161 }
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700162 ctx, err = r.setPrincipal(ctx, principal, shutdown, deps...)
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800163 if err != nil {
164 return nil, nil, nil, err
165 }
166
Asim Shankare89936f2015-04-22 17:37:43 -0700167 // Setup authenticated "networking"
168 ctx, err = r.WithNewStreamManager(ctx)
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800169 if err != nil {
170 return nil, nil, nil, err
171 }
172
Asim Shankare89936f2015-04-22 17:37:43 -0700173 return r, r.WithBackgroundContext(ctx), r.shutdown, nil
Matt Rosencrantz96d952a2015-01-15 09:18:38 -0800174}
175
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800176func (r *Runtime) addChild(ctx *context.T, me interface{}, stop func(), dependsOn ...interface{}) error {
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800177 if err := r.deps.Depend(me, dependsOn...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800178 stop()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800179 return err
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800180 } else if done := ctx.Done(); done != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800181 go func() {
182 <-done
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800183 finish := r.deps.CloseAndWait(me)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800184 stop()
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800185 finish()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800186 }()
187 }
188 return nil
189}
190
Matt Rosencrantz31995882015-01-27 20:00:48 -0800191func (r *Runtime) Init(ctx *context.T) error {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700192 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz31995882015-01-27 20:00:48 -0800193 return r.initMgmt(ctx)
194}
195
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800196func (r *Runtime) shutdown() {
Matt Rosencrantz5dbfbef2015-01-26 12:40:56 -0800197 r.deps.CloseAndWaitForAll()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800198 vlog.FlushLog()
199}
200
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800201func (r *Runtime) initSignalHandling(ctx *context.T) {
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800202 // TODO(caprita): Given that our device manager implementation is to
203 // kill all child apps when the device manager dies, we should
204 // enable SIGHUP on apps by default.
205
206 // Automatically handle SIGHUP to prevent applications started as
207 // daemons from being killed. The developer can choose to still listen
208 // on SIGHUP and take a different action if desired.
Matt Rosencrantzcf714c62015-01-22 16:15:56 -0800209 signals := make(chan os.Signal, 1)
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800210 signal.Notify(signals, syscall.SIGHUP)
211 go func() {
212 for {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800213 sig, ok := <-signals
214 if !ok {
215 break
216 }
217 vlog.Infof("Received signal %v", sig)
Suharsh Sivakumar628a8ee2015-01-14 11:38:56 -0800218 }
219 }()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800220 r.addChild(ctx, signals, func() {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800221 signal.Stop(signals)
222 close(signals)
223 })
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800224}
225
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800226func (*Runtime) NewEndpoint(ep string) (naming.Endpoint, error) {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700227 // nologcall
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800228 return inaming.NewEndpoint(ep)
229}
230
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700231func (r *Runtime) NewServer(ctx *context.T, opts ...rpc.ServerOpt) (rpc.Server, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700232 defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800233 // Create a new RoutingID (and StreamManager) for each server.
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800234 sm, err := newStreamManager()
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800235 if err != nil {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700236 return nil, fmt.Errorf("failed to create rpc/stream/Manager: %v", err)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800237 }
238
Todd Wang5082a552015-04-02 10:56:11 -0700239 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800240 principal, _ := ctx.Value(principalKey).(security.Principal)
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700241 client, _ := ctx.Value(clientKey).(rpc.Client)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800242
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700243 otherOpts := append([]rpc.ServerOpt{}, opts...)
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700244
245 if reservedDispatcher := r.GetReservedNameDispatcher(ctx); reservedDispatcher != nil {
246 otherOpts = append(otherOpts, irpc.ReservedNameDispatcher{
247 Dispatcher: reservedDispatcher,
248 })
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800249 }
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800250
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700251 id, _ := ctx.Value(initKey).(*initData)
252 if id.protocols != nil {
253 otherOpts = append(otherOpts, irpc.PreferredServerResolveProtocols(id.protocols))
254 }
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800255 if !hasServerBlessingsOpt(opts) && principal != nil {
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700256 otherOpts = append(otherOpts, options.ServerBlessings{
257 Blessings: principal.BlessingStore().Default(),
258 })
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800259 }
Cosmos Nicolaou00fe9a42015-04-24 14:18:01 -0700260 server, err := irpc.InternalNewServer(ctx, sm, ns, id.settingsPublisher, id.settingsName, r.GetClient(ctx), principal, otherOpts...)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800261 if err != nil {
262 return nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800263 }
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800264 stop := func() {
265 if err := server.Stop(); err != nil {
266 vlog.Errorf("A server could not be stopped: %v", err)
267 }
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800268 sm.Shutdown()
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800269 }
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700270 deps := []interface{}{client, vtraceDependency{}}
271 if principal != nil {
272 deps = append(deps, principal)
273 }
274 if err = r.addChild(ctx, server, stop, deps...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800275 return nil, err
276 }
277 return server, nil
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800278}
279
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700280func hasServerBlessingsOpt(opts []rpc.ServerOpt) bool {
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800281 for _, o := range opts {
282 if _, ok := o.(options.ServerBlessings); ok {
283 return true
284 }
285 }
286 return false
287}
288
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800289func newStreamManager() (stream.Manager, error) {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800290 rid, err := naming.NewRoutingID()
291 if err != nil {
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800292 return nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800293 }
294 sm := imanager.InternalNew(rid)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800295 return sm, nil
296}
297
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800298func (r *Runtime) setNewStreamManager(ctx *context.T) (*context.T, error) {
299 sm, err := newStreamManager()
300 if err != nil {
301 return nil, err
302 }
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800303 newctx := context.WithValue(ctx, streamManagerKey, sm)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800304 if err = r.addChild(ctx, sm, sm.Shutdown); err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800305 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800306 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800307 return newctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800308}
309
Todd Wangad492042015-04-17 15:58:40 -0700310func (r *Runtime) WithNewStreamManager(ctx *context.T) (*context.T, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700311 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800312 newctx, err := r.setNewStreamManager(ctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800313 if err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800314 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800315 }
316
317 // Create a new client since it depends on the stream manager.
Todd Wangad492042015-04-17 15:58:40 -0700318 newctx, _, err = r.WithNewClient(newctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800319 if err != nil {
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800320 return ctx, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800321 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800322 return newctx, nil
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800323}
324
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700325func (r *Runtime) setPrincipal(ctx *context.T, principal security.Principal, shutdown func(), deps ...interface{}) (*context.T, error) {
Suharsh Sivakumar2c5d8102015-03-23 08:49:12 -0700326 if principal != nil {
327 // We uniquely identify a principal with "security/principal/<publicKey>"
328 principalName := "security/principal/" + principal.PublicKey().String()
329 stats.NewStringFunc(principalName+"/blessingstore", principal.BlessingStore().DebugString)
330 stats.NewStringFunc(principalName+"/blessingroots", principal.Roots().DebugString)
331 }
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700332 ctx = context.WithValue(ctx, principalKey, principal)
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700333 return ctx, r.addChild(ctx, principal, shutdown, deps...)
Suharsh Sivakumar5ca46642015-01-30 10:33:38 -0800334}
335
Todd Wangad492042015-04-17 15:58:40 -0700336func (r *Runtime) WithPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) {
Bogdan Caprita95bca142015-06-29 17:16:05 -0700337 defer apilog.LogCallf(ctx, "principal=%v", principal)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800338 var err error
339 newctx := ctx
340
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700341 // TODO(mattr, suharshs): If there user gives us some principal that has dependencies
342 // we don't know about, we will not honour those dependencies during shutdown.
343 // For example if they create an agent principal with some client, we don't know
344 // about that, so servers based of this new principal will not prevent the client
345 // from terminating early.
Matt Rosencrantz9837b272015-04-30 18:32:36 -0700346 if newctx, err = r.setPrincipal(ctx, principal, func() {}); err != nil {
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700347 return ctx, err
348 }
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -0800349 if newctx, err = r.setNewStreamManager(newctx); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800350 return ctx, err
351 }
Suharsh Sivakumar033a30e2015-01-07 13:54:43 -0800352 if newctx, _, err = r.setNewNamespace(newctx, r.GetNamespace(ctx).Roots()...); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800353 return ctx, err
354 }
Todd Wangad492042015-04-17 15:58:40 -0700355 if newctx, _, err = r.WithNewClient(newctx); err != nil {
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800356 return ctx, err
357 }
358
359 return newctx, nil
360}
361
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800362func (*Runtime) GetPrincipal(ctx *context.T) security.Principal {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700363 // nologcall
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800364 p, _ := ctx.Value(principalKey).(security.Principal)
365 return p
366}
367
Todd Wangad492042015-04-17 15:58:40 -0700368func (r *Runtime) WithNewClient(ctx *context.T, opts ...rpc.ClientOpt) (*context.T, rpc.Client, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700369 defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700370 otherOpts := append([]rpc.ClientOpt{}, opts...)
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800371
Suharsh Sivakumar2ad4e102015-03-17 21:23:37 -0700372 p, _ := ctx.Value(principalKey).(security.Principal)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800373 sm, _ := ctx.Value(streamManagerKey).(stream.Manager)
Todd Wang5082a552015-04-02 10:56:11 -0700374 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700375 otherOpts = append(otherOpts, imanager.DialTimeout(5*time.Minute))
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800376
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700377 if id, _ := ctx.Value(initKey).(*initData); id.protocols != nil {
378 otherOpts = append(otherOpts, irpc.PreferredProtocols(id.protocols))
Matt Rosencrantz9db8bc32015-01-13 09:01:55 -0800379 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700380 client, err := irpc.InternalNewClient(sm, ns, otherOpts...)
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800381 if err != nil {
382 return ctx, nil, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800383 }
Matt Rosencrantz19329122015-01-23 22:18:49 -0800384 newctx := context.WithValue(ctx, clientKey, client)
Matt Rosencrantz3dc01962015-03-16 14:16:01 -0700385 deps := []interface{}{sm, vtraceDependency{}}
386 if p != nil {
387 deps = append(deps, p)
388 }
389 if err = r.addChild(ctx, client, client.Close, deps...); err != nil {
Matt Rosencrantzaeed5d52015-01-14 15:18:34 -0800390 return ctx, nil, err
391 }
392 return newctx, client, err
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800393}
394
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700395func (*Runtime) GetClient(ctx *context.T) rpc.Client {
Cosmos Nicolaou0e4e3922015-06-10 16:30:09 -0700396 // nologcall
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700397 cl, _ := ctx.Value(clientKey).(rpc.Client)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800398 return cl
399}
400
Todd Wang5082a552015-04-02 10:56:11 -0700401func (r *Runtime) setNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) {
402 ns, err := inamespace.New(roots...)
Asim Shankar263c73b2015-03-19 18:31:26 -0700403 if err != nil {
404 return nil, nil, err
405 }
Matt Rosencrantz001644e2015-01-29 14:24:48 -0800406
407 if oldNS := r.GetNamespace(ctx); oldNS != nil {
408 ns.CacheCtl(oldNS.CacheCtl()...)
409 }
410
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800411 if err == nil {
412 ctx = context.WithValue(ctx, namespaceKey, ns)
413 }
414 return ctx, ns, err
415}
416
Todd Wangad492042015-04-17 15:58:40 -0700417func (r *Runtime) WithNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) {
Cosmos Nicolaouf3c19092015-05-27 17:53:37 -0700418 defer apilog.LogCallf(ctx, "roots...=%v", roots)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800419 newctx, ns, err := r.setNewNamespace(ctx, roots...)
420 if err != nil {
421 return ctx, nil, err
422 }
423
424 // Replace the client since it depends on the namespace.
Todd Wangad492042015-04-17 15:58:40 -0700425 newctx, _, err = r.WithNewClient(newctx)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800426 if err != nil {
427 return ctx, nil, err
428 }
429
430 return newctx, ns, err
431}
432
Todd Wang5082a552015-04-02 10:56:11 -0700433func (*Runtime) GetNamespace(ctx *context.T) namespace.T {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700434 // nologcall
Todd Wang5082a552015-04-02 10:56:11 -0700435 ns, _ := ctx.Value(namespaceKey).(namespace.T)
Matt Rosencrantz5845bf12015-01-06 13:05:21 -0800436 return ns
437}
438
Jiri Simsa6ac95222015-02-23 16:11:49 -0800439func (*Runtime) GetAppCycle(ctx *context.T) v23.AppCycle {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700440 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700441 id, _ := ctx.Value(initKey).(*initData)
442 return id.appCycle
Suharsh Sivakumar033a30e2015-01-07 13:54:43 -0800443}
444
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700445func (*Runtime) GetListenSpec(ctx *context.T) rpc.ListenSpec {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700446 // nologcall
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700447 ls, _ := ctx.Value(listenKey).(rpc.ListenSpec)
448 return ls
449}
450
451func (*Runtime) WithListenSpec(ctx *context.T, ls rpc.ListenSpec) *context.T {
Bogdan Caprita95bca142015-06-29 17:16:05 -0700452 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700453 return context.WithValue(ctx, listenKey, ls.Copy())
Suharsh Sivakumarac9feed2015-01-08 10:58:37 -0800454}
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800455
Todd Wangad492042015-04-17 15:58:40 -0700456func (*Runtime) WithBackgroundContext(ctx *context.T) *context.T {
Bogdan Caprita95bca142015-06-29 17:16:05 -0700457 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800458 // Note we add an extra context with a nil value here.
459 // This prevents users from travelling back through the
460 // chain of background contexts.
461 ctx = context.WithValue(ctx, backgroundKey, nil)
462 return context.WithValue(ctx, backgroundKey, ctx)
463}
464
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800465func (*Runtime) GetBackgroundContext(ctx *context.T) *context.T {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700466 // nologcall
Matt Rosencrantz3838c552015-01-15 13:04:53 -0800467 bctx, _ := ctx.Value(backgroundKey).(*context.T)
468 if bctx == nil {
469 // There should always be a background context. If we don't find
470 // it, that means that the user passed us the background context
471 // in hopes of following the chain. Instead we just give them
472 // back what they sent in, which is correct.
473 return ctx
474 }
475 return bctx
476}
Robert Kroeger316442c2015-03-26 13:56:11 -0700477
Todd Wangad492042015-04-17 15:58:40 -0700478func (*Runtime) WithReservedNameDispatcher(ctx *context.T, d rpc.Dispatcher) *context.T {
Bogdan Caprita95bca142015-06-29 17:16:05 -0700479 defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700480 return context.WithValue(ctx, reservedNameKey, d)
Robert Kroeger316442c2015-03-26 13:56:11 -0700481}
482
483func (*Runtime) GetReservedNameDispatcher(ctx *context.T) rpc.Dispatcher {
Cosmos Nicolaouffc646e2015-05-06 22:33:51 -0700484 // nologcall
Matt Rosencrantzbf0d9d92015-04-08 12:43:14 -0700485 if d, ok := ctx.Value(reservedNameKey).(rpc.Dispatcher); ok {
486 return d
Robert Kroeger316442c2015-03-26 13:56:11 -0700487 }
488 return nil
489}