| 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 | |
| 10 "mojo/public/go/bindings" | |
| 11 "mojo/public/go/system" | |
| 12 | |
| 13 sp "mojo/public/interfaces/application/service_provider" | |
| 14 "mojo/public/interfaces/bindings/service_describer" | |
| 15 ) | |
| 16 | |
| 17 type connectionInfo struct { | |
| 18 requestorURL string | |
| 19 connectionURL string | |
| 20 } | |
| 21 | |
| 22 // RequestorURL returns the URL of application that established the connection. | |
| 23 func (c *connectionInfo) RequestorURL() string { | |
| 24 return c.requestorURL | |
| 25 } | |
| 26 | |
| 27 // ConnectionURL returns the URL that was used by the source application to | |
| 28 // establish a connection to the destination application. | |
| 29 func (c *connectionInfo) ConnectionURL() string { | |
| 30 return c.connectionURL | |
| 31 } | |
| 32 | |
| 33 // ServiceRequest is an interface request for a specified mojo service. | |
| 34 type ServiceRequest interface { | |
| 35 // Name returns the name of requested mojo service. | |
| 36 Name() string | |
| 37 | |
| 38 // ServiceDescription returns a service description, which can be querie
d to | |
| 39 // examine the type information of the service associated with this | |
| 40 // ServiceRequest. | |
| 41 // Note: In some implementations, the ServiceDescription returned will n
ot | |
| 42 // provide type information. Methods called may return nil or an error. | |
| 43 ServiceDescription() service_describer.ServiceDescription | |
| 44 | |
| 45 // PassMessagePipe passes ownership of the underlying message pipe | |
| 46 // handle to the newly created handle object, invalidating the | |
| 47 // underlying handle object in the process. | |
| 48 PassMessagePipe() system.MessagePipeHandle | |
| 49 } | |
| 50 | |
| 51 // ServiceFactory provides implementation of a mojo service. | |
| 52 type ServiceFactory interface { | |
| 53 // Name returns the name of provided mojo service. | |
| 54 Name() string | |
| 55 | |
| 56 // ServiceDescription returns a service description, which can be querie
d to | |
| 57 // examine the type information of the mojo service associated with this | |
| 58 // ServiceFactory. | |
| 59 // Note: In some implementations, the ServiceDescription returned will n
ot | |
| 60 // provide type information. Methods called may return nil or an error. | |
| 61 ServiceDescription() service_describer.ServiceDescription | |
| 62 | |
| 63 // Create binds an implementation of mojo service to the provided | |
| 64 // message pipe and runs it. | |
| 65 Create(pipe system.MessagePipeHandle) | |
| 66 } | |
| 67 | |
| 68 // Connection represents a connection to another application. An instance of | |
| 69 // this struct is passed to Delegate's AcceptConnection() function each time a | |
| 70 // connection is made to this application. | |
| 71 // TODO(vtl): This is largely overkill now that we no longer have "wrong way" | |
| 72 // service providers (a.k.a. "exposed services"). Things should be simplified. | |
| 73 // https://github.com/domokit/mojo/issues/762 | |
| 74 type Connection struct { | |
| 75 connectionInfo | |
| 76 // Request for local services. Is valid until ProvideServices is called. | |
| 77 servicesRequest *sp.ServiceProvider_Request | |
| 78 // Indicates that ProvideServices function was already called. | |
| 79 servicesProvided bool | |
| 80 localServices *bindings.Stub | |
| 81 outgoingConnection *OutgoingConnection | |
| 82 isClosed bool | |
| 83 // Is set if ProvideServicesWithDescriber was called. | |
| 84 // Note: When DescribeServices is invoked, some implementations may retu
rn | |
| 85 // incomplete ServiceDescriptions. For example, if type information was
not | |
| 86 // generated, then the methods called may return nil or an error. | |
| 87 describer *ServiceDescriberFactory | |
| 88 } | |
| 89 | |
| 90 func newConnection(requestorURL string, services sp.ServiceProvider_Request, res
olvedURL string) *Connection { | |
| 91 info := connectionInfo{ | |
| 92 requestorURL, | |
| 93 resolvedURL, | |
| 94 } | |
| 95 return &Connection{ | |
| 96 connectionInfo: info, | |
| 97 servicesRequest: &services, | |
| 98 outgoingConnection: &OutgoingConnection{ | |
| 99 info, | |
| 100 nil, | |
| 101 }, | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 // ProvideServices starts a service provider on a separate goroutine that | |
| 106 // provides given services to the remote application. Returns a pointer to | |
| 107 // outgoing connection that can be used to connect to services provided by | |
| 108 // remote application. | |
| 109 // Panics if called more than once. | |
| 110 func (c *Connection) ProvideServices(services ...ServiceFactory) *OutgoingConnec
tion { | |
| 111 if c.servicesProvided { | |
| 112 panic("ProvideServices or ProvideServicesWithDescriber can be ca
lled only once") | |
| 113 } | |
| 114 c.servicesProvided = true | |
| 115 if c.servicesRequest == nil { | |
| 116 return c.outgoingConnection | |
| 117 } | |
| 118 if len(services) == 0 { | |
| 119 c.servicesRequest.PassMessagePipe().Close() | |
| 120 return c.outgoingConnection | |
| 121 } | |
| 122 | |
| 123 provider := &serviceProviderImpl{ | |
| 124 make(map[string]ServiceFactory), | |
| 125 } | |
| 126 for _, service := range services { | |
| 127 provider.AddService(service) | |
| 128 } | |
| 129 c.localServices = sp.NewServiceProviderStub(*c.servicesRequest, provider
, bindings.GetAsyncWaiter()) | |
| 130 go func() { | |
| 131 for { | |
| 132 if err := c.localServices.ServeRequest(); err != nil { | |
| 133 connectionError, ok := err.(*bindings.Connection
Error) | |
| 134 if !ok || !connectionError.Closed() { | |
| 135 log.Println(err) | |
| 136 } | |
| 137 break | |
| 138 } | |
| 139 } | |
| 140 }() | |
| 141 return c.outgoingConnection | |
| 142 } | |
| 143 | |
| 144 // ProvideServicesWithDescriber is an alternative to ProvideServices that, in | |
| 145 // addition to providing the given services, also provides type descriptions of | |
| 146 // the given services. See ProvideServices for a description of what it does. | |
| 147 // This method will invoke ProvideServices after appending the ServiceDescriber | |
| 148 // service to |services|. See service_describer.mojom for a description of the | |
| 149 // ServiceDescriber interface. Client Mojo applications can choose to connect | |
| 150 // to this ServiceDescriber interface, which describes the other services listed | |
| 151 // in |services|. | |
| 152 // Note that the implementation of ServiceDescriber will make the optional | |
| 153 // DeclarationData available on all types, and in particular, the names used in | |
| 154 // .mojom files will be exposed to client applications. | |
| 155 func (c *Connection) ProvideServicesWithDescriber(services ...ServiceFactory) *O
utgoingConnection { | |
| 156 if c.servicesProvided { | |
| 157 panic("ProvideServices or ProvideServicesWithDescriber can be ca
lled only once") | |
| 158 } | |
| 159 mapping := make(map[string]service_describer.ServiceDescription) | |
| 160 for _, service := range services { | |
| 161 mapping[service.Name()] = service.ServiceDescription() | |
| 162 } | |
| 163 c.describer = newServiceDescriberFactory(mapping) | |
| 164 servicesWithDescriber := append(services, &service_describer.ServiceDesc
riber_ServiceFactory{c.describer}) | |
| 165 | |
| 166 return c.ProvideServices(servicesWithDescriber...) | |
| 167 } | |
| 168 | |
| 169 // Close closes both incoming and outgoing parts of the connection. | |
| 170 func (c *Connection) Close() { | |
| 171 if c.servicesRequest != nil { | |
| 172 c.servicesRequest.Close() | |
| 173 } | |
| 174 if c.localServices != nil { | |
| 175 c.localServices.Close() | |
| 176 } | |
| 177 if c.describer != nil { | |
| 178 c.describer.Close() | |
| 179 } | |
| 180 if c.outgoingConnection.remoteServices != nil { | |
| 181 c.outgoingConnection.remoteServices.Close_Proxy() | |
| 182 } | |
| 183 c.isClosed = true | |
| 184 } | |
| 185 | |
| 186 // OutgoingConnection represents outgoing part of connection to another | |
| 187 // application. In order to close it close the |Connection| object that returned | |
| 188 // this |OutgoingConnection|. | |
| 189 type OutgoingConnection struct { | |
| 190 connectionInfo | |
| 191 remoteServices *sp.ServiceProvider_Proxy | |
| 192 } | |
| 193 | |
| 194 // ConnectToService asks remote application to provide a service through the | |
| 195 // message pipe endpoint supplied by the caller. | |
| 196 func (c *OutgoingConnection) ConnectToService(request ServiceRequest) { | |
| 197 pipe := request.PassMessagePipe() | |
| 198 if c.remoteServices == nil { | |
| 199 pipe.Close() | |
| 200 return | |
| 201 } | |
| 202 c.remoteServices.ConnectToService(request.Name(), pipe) | |
| 203 } | |
| 204 | |
| 205 // serviceProviderImpl is an implementation of mojo ServiceProvider interface. | |
| 206 type serviceProviderImpl struct { | |
| 207 factories map[string]ServiceFactory | |
| 208 } | |
| 209 | |
| 210 // Mojo ServiceProvider implementation. | |
| 211 func (sp *serviceProviderImpl) ConnectToService(name string, messagePipe system.
MessagePipeHandle) error { | |
| 212 factory, ok := sp.factories[name] | |
| 213 if !ok { | |
| 214 messagePipe.Close() | |
| 215 return nil | |
| 216 } | |
| 217 factory.Create(messagePipe) | |
| 218 return nil | |
| 219 } | |
| 220 | |
| 221 func (sp *serviceProviderImpl) AddService(factory ServiceFactory) { | |
| 222 sp.factories[factory.Name()] = factory | |
| 223 } | |
| OLD | NEW |