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 |