Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
7737117a
Commit
7737117a
authored
Jan 25, 2016
by
Devon Carew
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1369 from devoncarew/improve_device_support
improve device notification support
parents
a46fb2c4
080896a3
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
99 additions
and
25 deletions
+99
-25
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+75
-22
daemon_test.dart
packages/flutter_tools/test/daemon_test.dart
+24
-3
No files found.
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
7737117a
...
...
@@ -6,6 +6,8 @@ import 'dart:async';
import
'dart:convert'
;
import
'dart:io'
;
import
'package:logging/logging.dart'
;
import
'../android/adb.dart'
;
import
'../android/device_android.dart'
;
import
'../base/logging.dart'
;
...
...
@@ -14,9 +16,7 @@ import '../runner/flutter_command.dart';
import
'start.dart'
;
import
'stop.dart'
as
stop
;
const
String
protocolVersion
=
'0.0.2'
;
// TODO(devoncarew): Pass logging data back to the client.
const
String
protocolVersion
=
'0.1.0'
;
/// A server process command. This command will start up a long-lived server.
/// It reads JSON-RPC based commands from stdin, executes them, and returns
...
...
@@ -28,6 +28,8 @@ class DaemonCommand extends FlutterCommand {
final
String
name
=
'daemon'
;
final
String
description
=
'Run a persistent, JSON-RPC based server to communicate with devices.'
;
bool
get
requiresProjectRoot
=>
false
;
Future
<
int
>
runInProject
()
async
{
print
(
'Starting device daemon...'
);
...
...
@@ -40,8 +42,6 @@ class DaemonCommand extends FlutterCommand {
return
JSON
.
decode
(
line
);
});
await
downloadApplicationPackagesAndConnectToDevices
();
Daemon
daemon
=
new
Daemon
(
commandStream
,
(
Map
command
)
{
stdout
.
writeln
(
'[
${JSON.encode(command, toEncodable: _jsonEncodeObject)}
]'
);
},
daemonCommand:
this
);
...
...
@@ -139,11 +139,11 @@ abstract class Domain {
String
toString
()
=>
name
;
void
handleCommand
(
String
name
,
dynamic
id
,
dynamic
args
)
{
void
handleCommand
(
String
command
,
dynamic
id
,
dynamic
args
)
{
new
Future
.
sync
(()
{
if
(
_handlers
.
containsKey
(
name
))
return
_handlers
[
name
](
args
);
throw
'command not understood:
$name
'
;
if
(
_handlers
.
containsKey
(
command
))
return
_handlers
[
command
](
args
);
throw
'command not understood:
$name
.
$command
'
;
}).
then
((
result
)
{
if
(
result
==
null
)
{
_send
({
'id'
:
id
});
...
...
@@ -152,12 +152,12 @@ abstract class Domain {
}
}).
catchError
((
error
,
trace
)
{
_send
({
'id'
:
id
,
'error'
:
_toJsonable
(
error
)});
logging
.
warning
(
'error handling
$name
'
,
error
,
trace
);
logging
.
warning
(
"error handling '
$name
.
$command
'"
,
error
,
trace
);
});
}
void
sendEvent
(
String
name
,
[
dynamic
args
])
{
Map
<
String
,
dynamic
>
map
=
{
'
method
'
:
name
};
Map
<
String
,
dynamic
>
map
=
{
'
event
'
:
name
};
if
(
args
!=
null
)
map
[
'params'
]
=
_toJsonable
(
args
);
_send
(
map
);
...
...
@@ -169,12 +169,33 @@ abstract class Domain {
}
/// This domain responds to methods like [version] and [shutdown].
///
/// This domain fires the `daemon.logMessage` event.
class
DaemonDomain
extends
Domain
{
DaemonDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'daemon'
)
{
registerHandler
(
'version'
,
version
);
registerHandler
(
'shutdown'
,
shutdown
);
_subscription
=
Logger
.
root
.
onRecord
.
listen
((
LogRecord
record
)
{
String
message
=
record
.
error
==
null
?
record
.
message
:
'
${record.message}
:
${record.error}
'
;
if
(
record
.
stackTrace
!=
null
)
{
sendEvent
(
'daemon.logMessage'
,
{
'level'
:
record
.
level
.
name
.
toLowerCase
(),
'message'
:
message
,
'stackTrace'
:
record
.
stackTrace
.
toString
()
});
}
else
{
sendEvent
(
'daemon.logMessage'
,
{
'level'
:
record
.
level
.
name
.
toLowerCase
(),
'message'
:
message
});
}
});
}
StreamSubscription
<
LogRecord
>
_subscription
;
Future
<
String
>
version
(
dynamic
args
)
{
return
new
Future
.
value
(
protocolVersion
);
}
...
...
@@ -183,6 +204,10 @@ class DaemonDomain extends Domain {
Timer
.
run
(()
=>
daemon
.
shutdown
());
return
new
Future
.
value
();
}
void
dispose
()
{
_subscription
?.
cancel
();
}
}
/// This domain responds to methods like [start] and [stopAll].
...
...
@@ -195,19 +220,46 @@ class AppDomain extends Domain {
registerHandler
(
'stopAll'
,
stopAll
);
}
Future
<
dynamic
>
start
(
dynamic
args
)
async
{
// TODO
: Add the ability to pass args: target, http, checked
Future
<
dynamic
>
start
(
Map
<
String
,
dynamic
>
args
)
async
{
// TODO
(devoncarew): We need to be able to specify the target device.
await
Future
.
wait
([
command
.
downloadToolchain
(),
command
.
downloadApplicationPackagesAndConnectToDevices
(),
],
eagerError:
true
);
if
(
args
[
'projectDirectory'
]
is
!
String
)
throw
"A 'projectDirectory' is required"
;
String
projectDirectory
=
args
[
'projectDirectory'
];
if
(!
FileSystemEntity
.
isDirectorySync
(
projectDirectory
))
throw
"The '
$projectDirectory
' does not exist"
;
// We change the current working directory for the duration of the `start`
// command. This would have race conditions with other commands happening in
// parallel and doesn't play well with the caching built into `FlutterCommand`.
// TODO(devoncarew): Make flutter_tools work better with commands run from any directory.
// TODO(devoncarew): Use less (or more explicit) caching.
Directory
cwd
=
Directory
.
current
;
Directory
.
current
=
new
Directory
(
projectDirectory
);
try
{
await
Future
.
wait
([
command
.
downloadToolchain
(),
command
.
downloadApplicationPackagesAndConnectToDevices
(),
],
eagerError:
true
);
int
result
=
await
startApp
(
command
.
devices
,
command
.
applicationPackages
,
command
.
toolchain
,
target:
args
[
'target'
],
route:
args
[
'route'
],
checked:
args
[
'checked'
]
??
true
);
if
(
result
!=
0
)
throw
'Error starting app:
$result
'
;
}
finally
{
Directory
.
current
=
cwd
;
}
return
startApp
(
command
.
devices
,
command
.
applicationPackages
,
command
.
toolchain
).
then
((
int
result
)
=>
null
);
return
null
;
}
Future
<
bool
>
stopAll
(
dynamic
args
)
{
...
...
@@ -328,6 +380,7 @@ class AndroidDeviceDiscovery {
Map
<
String
,
dynamic
>
_deviceToMap
(
Device
device
)
{
return
<
String
,
dynamic
>{
'id'
:
device
.
id
,
'name'
:
device
.
name
,
'platform'
:
_enumToString
(
device
.
platform
),
'available'
:
device
.
isConnected
()
};
...
...
packages/flutter_tools/test/daemon_test.dart
View file @
7737117a
...
...
@@ -4,6 +4,7 @@
import
'dart:async'
;
import
'package:flutter_tools/src/base/logging.dart'
;
import
'package:flutter_tools/src/commands/daemon.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:test/test.dart'
;
...
...
@@ -29,12 +30,30 @@ defineTests() {
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
commands
.
add
({
'id'
:
0
,
'method'
:
'daemon.version'
});
Map
response
=
await
responses
.
stream
.
first
;
Map
response
=
await
responses
.
stream
.
where
(
_notEvent
).
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
isNotEmpty
);
expect
(
response
[
'result'
]
is
String
,
true
);
});
test
(
'daemon.logMessage'
,
()
async
{
StreamController
<
Map
>
commands
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
daemon
=
new
Daemon
(
commands
.
stream
,
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
logging
.
warning
(
'daemon.logMessage test'
);
Map
response
=
await
responses
.
stream
.
where
((
Map
<
String
,
dynamic
>
map
)
{
return
map
[
'event'
]
==
'daemon.logMessage'
&&
map
[
'params'
][
'level'
]
==
'warning'
;
}).
first
;
expect
(
response
[
'id'
],
isNull
);
expect
(
response
[
'event'
],
'daemon.logMessage'
);
Map
<
String
,
String
>
logMessage
=
response
[
'params'
];
expect
(
logMessage
[
'level'
],
'warning'
);
expect
(
logMessage
[
'message'
],
'daemon.logMessage test'
);
});
test
(
'daemon.shutdown'
,
()
async
{
StreamController
<
Map
>
commands
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
...
...
@@ -72,7 +91,7 @@ defineTests() {
when
(
mockDevices
.
iOSSimulator
.
stopApp
(
any
)).
thenReturn
(
false
);
commands
.
add
({
'id'
:
0
,
'method'
:
'app.stopAll'
});
Map
response
=
await
responses
.
stream
.
first
;
Map
response
=
await
responses
.
stream
.
where
(
_notEvent
).
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
true
);
});
...
...
@@ -85,9 +104,11 @@ defineTests() {
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
commands
.
add
({
'id'
:
0
,
'method'
:
'device.getDevices'
});
Map
response
=
await
responses
.
stream
.
first
;
Map
response
=
await
responses
.
stream
.
where
(
_notEvent
).
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
isList
);
});
});
}
bool
_notEvent
(
Map
<
String
,
dynamic
>
map
)
=>
map
[
'event'
]
==
null
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment