| Index: third_party/mojo/src/mojo/public/go/application/application_impl.go
|
| diff --git a/third_party/mojo/src/mojo/public/go/application/application_impl.go b/third_party/mojo/src/mojo/public/go/application/application_impl.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..43a1eb83eff8a48ba3d5f030b8a718a4c7a8f733
|
| --- /dev/null
|
| +++ b/third_party/mojo/src/mojo/public/go/application/application_impl.go
|
| @@ -0,0 +1,167 @@
|
| +// Copyright 2015 The Chromium 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 application
|
| +
|
| +import (
|
| + "log"
|
| + "sync"
|
| +
|
| + "mojo/public/go/bindings"
|
| + "mojo/public/go/system"
|
| +
|
| + "mojo/public/interfaces/application/application"
|
| + sp "mojo/public/interfaces/application/service_provider"
|
| + "mojo/public/interfaces/application/shell"
|
| +)
|
| +
|
| +// Delegate is an interface that your mojo application should implement.
|
| +// All methods are called from the same goroutine to make sure that order of
|
| +// calls matches the order of messages sent to underlying message pipe.
|
| +type Delegate interface {
|
| + // Initialize is called exactly once before any other method.
|
| + Initialize(ctx Context)
|
| +
|
| + // AcceptConnection is called when another application attempts to open
|
| + // a connection to this application. Close the connection if you no
|
| + // longer need it.
|
| + AcceptConnection(connection *Connection)
|
| +
|
| + // Quit is called to request the application shut itself down
|
| + // gracefully.
|
| + Quit()
|
| +}
|
| +
|
| +// Context is an interface to information about mojo application environment.
|
| +type Context interface {
|
| + // URL returns the URL the application was found at, after all mappings,
|
| + // resolution, and redirects.
|
| + URL() string
|
| +
|
| + // Args returns a list of initial configuration arguments, passed by the
|
| + // Shell.
|
| + Args() []string
|
| +
|
| + // ConnectToApplication requests a new connection to an application. You
|
| + // should pass a list of services you want to provide to the requested
|
| + // application.
|
| + ConnectToApplication(remoteURL string, providedServices ...ServiceFactory) *OutgoingConnection
|
| +}
|
| +
|
| +// ApplicationImpl is an utility class for communicating with the Shell, and
|
| +// providing Services to clients.
|
| +type ApplicationImpl struct {
|
| + shell *shell.ShellProxy
|
| + args []string
|
| + url string
|
| + // Pointer to the stub that runs this instance of ApplicationImpl.
|
| + runner *bindings.Stub
|
| + quitOnce sync.Once
|
| +
|
| + delegate Delegate
|
| + // Protects connections, that can be modified concurrently because of
|
| + // ConnectToApplication calls.
|
| + mu sync.Mutex
|
| + connections []*Connection
|
| +}
|
| +
|
| +// Run binds your mojo application to provided message pipe handle and runs it
|
| +// until the application is terminated.
|
| +func Run(delegate Delegate, applicationRequest system.MojoHandle) {
|
| + messagePipe := system.GetCore().AcquireNativeHandle(applicationRequest).ToMessagePipeHandle()
|
| + appRequest := application.ApplicationRequest{bindings.NewMessagePipeHandleOwner(messagePipe)}
|
| + impl := &ApplicationImpl{
|
| + delegate: delegate,
|
| + }
|
| + stub := application.NewApplicationStub(appRequest, impl, bindings.GetAsyncWaiter())
|
| + impl.runner = stub
|
| + for {
|
| + if err := stub.ServeRequest(); err != nil {
|
| + // TODO(rogulenko): don't log in case message pipe was closed
|
| + log.Println(err)
|
| + impl.RequestQuit()
|
| + break
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Mojo application implementation.
|
| +func (impl *ApplicationImpl) Initialize(shellPointer shell.ShellPointer, args *[]string, url string) error {
|
| + impl.shell = shell.NewShellProxy(shellPointer, bindings.GetAsyncWaiter())
|
| + if args != nil {
|
| + impl.args = *args
|
| + }
|
| + impl.url = url
|
| + impl.delegate.Initialize(impl)
|
| + return nil
|
| +}
|
| +
|
| +// Mojo application implementation.
|
| +func (impl *ApplicationImpl) AcceptConnection(requestorURL string, services *sp.ServiceProviderRequest, exposedServices *sp.ServiceProviderPointer, resolvedURL string) error {
|
| + connection := newConnection(requestorURL, services, exposedServices, resolvedURL)
|
| + impl.delegate.AcceptConnection(connection)
|
| + impl.addConnection(connection)
|
| + return nil
|
| +}
|
| +
|
| +// Mojo application implementation.
|
| +func (impl *ApplicationImpl) RequestQuit() error {
|
| + impl.quitOnce.Do(func() {
|
| + impl.delegate.Quit()
|
| + impl.mu.Lock()
|
| + for _, c := range impl.connections {
|
| + c.Close()
|
| + }
|
| + impl.mu.Unlock()
|
| + impl.shell.Close_proxy()
|
| + impl.runner.Close()
|
| + })
|
| + return nil
|
| +}
|
| +
|
| +// Context implementaion.
|
| +func (impl *ApplicationImpl) URL() string {
|
| + return impl.url
|
| +}
|
| +
|
| +// Context implementaion.
|
| +func (impl *ApplicationImpl) Args() []string {
|
| + return impl.args
|
| +}
|
| +
|
| +// Context implementaion.
|
| +func (impl *ApplicationImpl) ConnectToApplication(remoteURL string, providedServices ...ServiceFactory) *OutgoingConnection {
|
| + servicesRequest, servicesPointer := sp.CreateMessagePipeForServiceProvider()
|
| + exposedServicesRequest, exposedServicesPointer := sp.CreateMessagePipeForServiceProvider()
|
| + if err := impl.shell.ConnectToApplication(remoteURL, &servicesRequest, &exposedServicesPointer); err != nil {
|
| + log.Printf("can't connect to %v: %v", remoteURL, err)
|
| + // In case of error message pipes sent through Shell are closed and
|
| + // the connection will work as if the remote application closed
|
| + // both ServiceProvider's pipes.
|
| + }
|
| + connection := newConnection(impl.url, &exposedServicesRequest, &servicesPointer, remoteURL)
|
| + impl.addConnection(connection)
|
| + return connection.ProvideServices(providedServices...)
|
| +}
|
| +
|
| +// addConnection appends connections slice by a provided connection, removing
|
| +// connections that have been closed.
|
| +func (impl *ApplicationImpl) addConnection(c *Connection) {
|
| + impl.mu.Lock()
|
| + i := 0
|
| + for i < len(impl.connections) {
|
| + if impl.connections[i].isClosed {
|
| + last := len(impl.connections) - 1
|
| + impl.connections[i] = impl.connections[last]
|
| + impl.connections[last] = nil
|
| + impl.connections = impl.connections[:last]
|
| + } else {
|
| + i++
|
| + }
|
| + }
|
| + if !c.isClosed {
|
| + impl.connections = append(impl.connections, c)
|
| + }
|
| + impl.mu.Unlock()
|
| +}
|
|
|