| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package application | |
| 6 | |
| 7 import ( | |
| 8 "log" | |
| 9 "sync" | |
| 10 | |
| 11 "mojo/public/go/bindings" | |
| 12 "mojo/public/go/system" | |
| 13 | |
| 14 "mojo/public/interfaces/application/application" | |
| 15 sp "mojo/public/interfaces/application/service_provider" | |
| 16 "mojo/public/interfaces/application/shell" | |
| 17 ) | |
| 18 | |
| 19 // Delegate is an interface that your mojo application should implement. | |
| 20 // All methods are called from the same goroutine to make sure that order of | |
| 21 // calls matches the order of messages sent to underlying message pipe. | |
| 22 type Delegate interface { | |
| 23 // Initialize is called exactly once before any other method. | |
| 24 Initialize(ctx Context) | |
| 25 | |
| 26 // AcceptConnection is called when another application attempts to open | |
| 27 // a connection to this application. Close the connection if you no | |
| 28 // longer need it. | |
| 29 AcceptConnection(connection *Connection) | |
| 30 | |
| 31 // Quit is called to request the application shut itself down | |
| 32 // gracefully. | |
| 33 Quit() | |
| 34 } | |
| 35 | |
| 36 // Context is an interface to information about mojo application environment. | |
| 37 type Context interface { | |
| 38 // URL returns the URL the application was found at, after all mappings, | |
| 39 // resolution, and redirects. | |
| 40 URL() string | |
| 41 | |
| 42 // Args returns a list of initial configuration arguments, passed by the | |
| 43 // Shell. | |
| 44 Args() []string | |
| 45 | |
| 46 // ConnectToApplication requests a new connection to an application. | |
| 47 ConnectToApplication(remoteURL string) *OutgoingConnection | |
| 48 | |
| 49 // Close closes the main run loop for this application. | |
| 50 Close() | |
| 51 } | |
| 52 | |
| 53 // ApplicationImpl is an utility class for communicating with the Shell, and | |
| 54 // providing Services to clients. | |
| 55 type ApplicationImpl struct { | |
| 56 shell *shell.Shell_Proxy | |
| 57 args []string | |
| 58 url string | |
| 59 // Pointer to the stub that runs this instance of ApplicationImpl. | |
| 60 runner *bindings.Stub | |
| 61 quitOnce sync.Once | |
| 62 | |
| 63 delegate Delegate | |
| 64 // Protects connections, that can be modified concurrently because of | |
| 65 // ConnectToApplication calls. | |
| 66 mu sync.Mutex | |
| 67 connections []*Connection | |
| 68 } | |
| 69 | |
| 70 // Run binds your mojo application to provided message pipe handle and runs it | |
| 71 // until the application is terminated. | |
| 72 func Run(delegate Delegate, applicationRequest system.MojoHandle) { | |
| 73 messagePipe := system.GetCore().AcquireNativeHandle(applicationRequest).
ToMessagePipeHandle() | |
| 74 appRequest := application.Application_Request{bindings.NewMessagePipeHan
dleOwner(messagePipe)} | |
| 75 impl := &ApplicationImpl{ | |
| 76 delegate: delegate, | |
| 77 } | |
| 78 stub := application.NewApplicationStub(appRequest, impl, bindings.GetAsy
ncWaiter()) | |
| 79 impl.runner = stub | |
| 80 for { | |
| 81 if err := stub.ServeRequest(); err != nil { | |
| 82 connectionError, ok := err.(*bindings.ConnectionError) | |
| 83 if !ok || !connectionError.Closed() { | |
| 84 log.Println(err) | |
| 85 } | |
| 86 impl.RequestQuit() | |
| 87 break | |
| 88 } | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 // Mojo application implementation. | |
| 93 func (impl *ApplicationImpl) Initialize(shellPointer shell.Shell_Pointer, args *
[]string, url string) error { | |
| 94 impl.shell = shell.NewShellProxy(shellPointer, bindings.GetAsyncWaiter()
) | |
| 95 if args != nil { | |
| 96 impl.args = *args | |
| 97 } | |
| 98 impl.url = url | |
| 99 impl.delegate.Initialize(impl) | |
| 100 return nil | |
| 101 } | |
| 102 | |
| 103 // Mojo application implementation. | |
| 104 func (impl *ApplicationImpl) AcceptConnection(requestorURL string, resolvedURL s
tring, services sp.ServiceProvider_Request) error { | |
| 105 connection := newConnection(requestorURL, services, resolvedURL) | |
| 106 impl.delegate.AcceptConnection(connection) | |
| 107 impl.addConnection(connection) | |
| 108 return nil | |
| 109 } | |
| 110 | |
| 111 // Mojo application implementation. | |
| 112 func (impl *ApplicationImpl) RequestQuit() error { | |
| 113 impl.quitOnce.Do(func() { | |
| 114 impl.delegate.Quit() | |
| 115 impl.mu.Lock() | |
| 116 for _, c := range impl.connections { | |
| 117 c.Close() | |
| 118 } | |
| 119 impl.mu.Unlock() | |
| 120 impl.shell.Close_Proxy() | |
| 121 impl.runner.Close() | |
| 122 }) | |
| 123 return nil | |
| 124 } | |
| 125 | |
| 126 // Context implementaion. | |
| 127 func (impl *ApplicationImpl) URL() string { | |
| 128 return impl.url | |
| 129 } | |
| 130 | |
| 131 // Context implementaion. | |
| 132 func (impl *ApplicationImpl) Args() []string { | |
| 133 return impl.args | |
| 134 } | |
| 135 | |
| 136 // Context implementaion. | |
| 137 func (impl *ApplicationImpl) ConnectToApplication(remoteURL string) *OutgoingCon
nection { | |
| 138 servicesRequest, servicesPointer := sp.CreateMessagePipeForServiceProvid
er() | |
| 139 if err := impl.shell.ConnectToApplication(remoteURL, servicesRequest); e
rr != nil { | |
| 140 log.Printf("can't connect to %v: %v", remoteURL, err) | |
| 141 // In case of error message pipes sent through Shell are closed
and | |
| 142 // the connection will work as if the remote application closed | |
| 143 // both ServiceProvider's pipes. | |
| 144 } | |
| 145 return &OutgoingConnection{ | |
| 146 connectionInfo{ | |
| 147 impl.url, | |
| 148 remoteURL, | |
| 149 }, | |
| 150 sp.NewServiceProviderProxy(servicesPointer, bindings.GetAsyncWai
ter()), | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 func (impl *ApplicationImpl) Close() { | |
| 155 impl.RequestQuit() | |
| 156 } | |
| 157 | |
| 158 // addConnection appends connections slice by a provided connection, removing | |
| 159 // connections that have been closed. | |
| 160 func (impl *ApplicationImpl) addConnection(c *Connection) { | |
| 161 impl.mu.Lock() | |
| 162 i := 0 | |
| 163 for i < len(impl.connections) { | |
| 164 if impl.connections[i].isClosed { | |
| 165 last := len(impl.connections) - 1 | |
| 166 impl.connections[i] = impl.connections[last] | |
| 167 impl.connections[last] = nil | |
| 168 impl.connections = impl.connections[:last] | |
| 169 } else { | |
| 170 i++ | |
| 171 } | |
| 172 } | |
| 173 if !c.isClosed { | |
| 174 impl.connections = append(impl.connections, c) | |
| 175 } | |
| 176 impl.mu.Unlock() | |
| 177 } | |
| OLD | NEW |