1#!/usr/bin/env python 2# Copyright 2013 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6# Interactive test script for the Chromoting host native messaging component. 7 8import json 9import readline 10import struct 11import subprocess 12import sys 13 14 15def PrintMenuAndGetBuilder(messages): 16 print 17 for i in range(0, len(messages)): 18 print '%d: %s' % (i + 1, messages[i][0]) 19 print 'Q: Quit' 20 while True: 21 choice = raw_input('Enter choice: ') 22 if choice.lower() == 'q': 23 return None 24 choice = int(choice) 25 if choice >= 1 and choice <= len(messages): 26 return messages[choice - 1][1] 27 28 29# Message builder methods. 30def BuildHello(): 31 return {'type': 'hello'} 32 33 34def BuildClearAllPairedClients(): 35 return {'type': 'clearPairedClients'} 36 37 38def BuildDeletePairedClient(): 39 client_id = raw_input('Enter client id: ') 40 return {'type': 'deletePairedClient', 41 'clientId': client_id} 42 43 44def BuildGetHostName(): 45 return {'type': 'getHostName'} 46 47 48def BuildGetPinHash(): 49 host_id = raw_input('Enter host id: ') 50 pin = raw_input('Enter PIN: ') 51 return {'type': 'getPinHash', 52 'hostId': host_id, 53 'pin': pin} 54 55 56def BuildGenerateKeyPair(): 57 return {'type': 'generateKeyPair'} 58 59 60def BuildUpdateDaemonConfig(): 61 config_json = raw_input('Enter config JSON: ') 62 return {'type': 'updateDaemonConfig', 63 'config': config_json} 64 65 66def BuildGetDaemonConfig(): 67 return {'type': 'getDaemonConfig'} 68 69 70def BuildGetPairedClients(): 71 return {'type': 'getPairedClients'} 72 73 74def BuildGetUsageStatsConsent(): 75 return {'type': 'getUsageStatsConsent'} 76 77 78def BuildStartDaemon(): 79 while True: 80 consent = raw_input('Report usage stats [y/n]? ') 81 if consent.lower() == 'y': 82 consent = True 83 elif consent.lower() == 'n': 84 consent = False 85 else: 86 continue 87 break 88 config_json = raw_input('Enter config JSON: ') 89 return {'type': 'startDaemon', 90 'consent': consent, 91 'config': config_json} 92 93 94def BuildStopDaemon(): 95 return {'type': 'stopDaemon'} 96 97 98def BuildGetDaemonState(): 99 return {'type': 'getDaemonState'} 100 101 102def main(): 103 if len(sys.argv) != 2: 104 print 'Usage: ' + sys.argv[0] + ' <path to native messaging host>' 105 sys.exit(1) 106 107 native_messaging_host = sys.argv[1] 108 109 child = subprocess.Popen(native_messaging_host, stdin=subprocess.PIPE, 110 stdout=subprocess.PIPE, close_fds=True) 111 112 message_id = 0 113 while True: 114 messages = [ 115 ('Hello', BuildHello), 116 ('Clear all paired clients', BuildClearAllPairedClients), 117 ('Delete paired client', BuildDeletePairedClient), 118 ('Get host name', BuildGetHostName), 119 ('Get PIN hash', BuildGetPinHash), 120 ('Generate key pair', BuildGenerateKeyPair), 121 ('Update daemon config', BuildUpdateDaemonConfig), 122 ('Get daemon config', BuildGetDaemonConfig), 123 ('Get paired clients', BuildGetPairedClients), 124 ('Get usage stats consent', BuildGetUsageStatsConsent), 125 ('Start daemon', BuildStartDaemon), 126 ('Stop daemon', BuildStopDaemon), 127 ('Get daemon state', BuildGetDaemonState) 128 ] 129 builder = PrintMenuAndGetBuilder(messages) 130 if not builder: 131 break 132 message_dict = builder() 133 message_dict['id'] = message_id 134 message = json.dumps(message_dict) 135 message_id += 1 136 print 'Message: ' + message 137 child.stdin.write(struct.pack('I', len(message))) 138 child.stdin.write(message) 139 child.stdin.flush() 140 141 reply_length_bytes = child.stdout.read(4) 142 if len(reply_length_bytes) < 4: 143 print 'Invalid message length' 144 break 145 reply_length = struct.unpack('i', reply_length_bytes)[0] 146 reply = child.stdout.read(reply_length).decode('utf-8') 147 print 'Reply: ' + reply 148 if len(reply) != reply_length: 149 print 'Invalid reply length' 150 break 151 152if __name__ == '__main__': 153 main() 154