trphoenix
2018-11-28 117664259ffca2f16ec47c5672012dfb6704b5ab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
part of redux_remote_devtools;
 
class RemoteDevToolsMiddleware extends MiddlewareClass {
  /**
   * The remote-devtools server to connect to. Should include
   * protocol and port if necessary. For example:
   * 
   * example.lan:8000
   * 
   */
  String _host;
  SocketClusterWrapper socket;
  Store store;
  String _channel;
  bool _started = false;
 
  ActionEncoder actionEncoder;
  StateEncoder stateEncoder;
 
  RemoteDevToolsMiddleware(this._host,
      {this.actionEncoder = const JsonActionEncoder(),
      this.stateEncoder = const JsonStateEncoder(),
      this.socket}) {
    if (socket == null) {
      this.socket =
          new SocketClusterWrapper('ws://${this._host}/socketcluster/');
    }
  }
 
  connect() async {
    await this.socket.connect();
    this._channel = await this._login();
    this._relay('START');
    _started = true;
    this.socket.on(_channel, (String name, dynamic data) {
      this.handleEventFromRemote(data as Map<String, dynamic>);
    });
    if (this.store != null) {
      this._relay('ACTION', store.state, 'CONNECT');
    }
  }
 
  Future<String> _login() {
    Completer<String> c = new Completer<String>();
    this.socket.emit('login', 'master',
        (String name, dynamic error, dynamic data) {
      c.complete(data as String);
    });
    return c.future;
  }
 
  _relay(String type, [Object state, dynamic action, String nextActionId]) {
    var message = {'type': type, 'id': socket.id, 'name': 'flutter'};
 
    if (state != null) {
      message['payload'] = this.stateEncoder.encode(state);
    }
    if (type == 'ACTION') {
      message['action'] = this.actionEncoder.encode(action);
      message['nextActionId'] = nextActionId;
    } else if (action != null) {
      message['action'] = action as String;
    }
    socket.emit(this.socket.id != null ? 'log' : 'log-noid', message);
  }
 
  void handleEventFromRemote(Map<String, dynamic> data) {
    switch (data['type'] as String) {
      case 'DISPATCH':
        _handleDispatch(data['action']);
        break;
      default:
        print('Unknown type:' + data['type'].toString());
    }
  }
 
  void _handleDispatch(dynamic action) {
    switch (action['type'] as String) {
      case 'JUMP_TO_STATE':
        if (this.store != null) {
          this
              .store
              .dispatch(new DevToolsAction.jumpToState(action['index'] as int));
        } else {
          print('No store reference set, cannot dispatch remote action');
        }
        break;
    }
  }
 
  /// Middleware function called by redux, dispatches actions to devtools
  call(Store store, dynamic action, NextDispatcher next) {
    next(action);
    if (_started && !(action is DevToolsAction)) {
      this._relay('ACTION', store.state, action);
    }
  }
}