UNPKG

smartfacecloud-emulator-dispatcher

Version:

Handles Emulator Dispatcher Part of SmartfaceCloud

329 lines (232 loc) 10.1 kB
# Dispatcher Analysis Dispatcher is like a proxy gateway service that provides communication between emulator and IDE. In this scenario emulator is client, IDE is server. All connections are using secure web sockets for each independent service. Currently 4 sockets are present: Control, File, Debug and UI. ## 1) Control Used to send commands and status messages and response. List of delta calculation is provided. Connection will present until user performs **Clear** operation from emulator. This is applicable other services as well. ## 2) File Used to transmit files from IDE to emulator. Emulator tells which files to get, then this service prepares files to be downloaded. After **getFiles** is received, dispatcher knows which files to send. Before creating zip file **resetTimeout** message is sent to device with interval as explained in detail below. After preparing zip, emulator is informed about the zip size by sending **fileSize** message. Then actual zip file is streamed over *FILE socket*. Then dispatcher stops sending **resetTimeout** messages. ### Creating zip Zip creation is performed on memory for performance. No compression is performed on zip which decreases memory usage dramatically for other processes. Emulator processes file paths with a URI scheme. (For example *script://[PATH_OF_SCRIPT]*) So a descriptor file is needed for storing a map of actual file path and URI. Because of that zip includes a descriptor file other than actual files to send. ### Delta Calculation This operation is performed to not to download any unchanged files. Delta calculation occurs on emulator side. IDE is generating full index. Emulator receives new index when it is going to update existing files. Emulator may or may not have an old index. If old index is not present, emulator is going to full download without going over the delta calculation. If old index is present, then emulator goes over by comparing two index values. For the same item with different value, emulator is going to download latest version of the same file. Emulator does not perform hash or validation, just scans the index. As the files downloaded from IDE to emulator are not subject to be changed by emulator programmatically. IDE will not be aware any file changed on emulator. User made changes are subject to their problem. Index data is stored as a single file. Which is called index file. Format of this data is JSON. ## 3) Debug Used to communicate with corresponding **debugger proxy** on IDE. If this connection is not established, the running project is not being debugged. ## 4) UI Provides communication between IDE UI and dispatcher itself. By IDE UI we mean dispatcher plugin running on browser. Log messages such as **console.log** are transmitted to dispatcher plugin using this service. When user wants to stop current debugging session from IDE UI, related request is sent to dispatcher using this service. ## Commands ### getIndex ---- **getIndex** is received from emulator from *CONTROL* socket and is used to get information about device. When this message is received, index is calculated with CRC's of each file. Then this information is sent with **getFiles** command which is explained below. ```javascript { "command": "getIndex", "data": { "brandModel": "<string>", "brandName": "<string>", "deviceID": "<string: Random GUID generated by emulator once>", "deviceName": "<string>", "os": "<string: name of the OS: iOS | Android>", "osVersion": "<number: Full version of the OS>", "resourceFolderOrder": [], "screen": { "pt": { "height": "<number>", "width": "<number>" }, "px": { "height": "<number>", "width": "<number>" } }, "screenDPI": "<number>", "smartfaceVersion": "<number: Full version of emulator>", }, "id": "<string: Random GUID generated by emulator once>", } ``` Update mechanism and storing index information is explained at **Delta Calculation** section. *resourceFolderOrder:* Android only data, iOS does not transmit this field. In a string array Android transmits which resource folders are used in order. Density names includes drawable prefixes too. ### getFiles ---- **getFiles** is used to send device **project.json** information including each file with CRC's calculated by dispatcher. This message is sent from *CONTROL* socket. Like below: ```javascript { "id": "<string: Random GUID>", "command": "getFiles", "data": { "api": {}, "build": {}, "config": {}, "files": [], "info": {}, "projectID": "<string>", "workspace": {} } } ``` In given example message, each field except for *deviceID* and *files*; denotes fields from **project.json**. When emulator receives **getFiles** command it decides which files to retrieve from dispatcher (**Delta Calculation** section). Then a message like below is sent to dispatcher (*FILE* socket) as a response: ```javascript { "command": "getFiles", "data": { "files": [] }, "id": "<string: Random GUID>" } ``` Not all files, but only the ones necessary is retrieved. Which files to be retrieved is under files array. ### keepAlive ---- ```javascript { "command": "keepAlive", "service": "<string: Service>" } ``` For *each socket* connected to dispatcher, **keepAlive** command is sent with predefined interval (15 secs). ### resetTimeout ---- When device is connected to dispatcher, if no message is sent for a minute (which is defined by emulator) connection is considered to be timed out. Which causes unwanted timeouts to occur when number of files to be sent is too much for instance. In order to solve this, **resetTimeout** is implemented. **resetTimeout** is sent from dispatcher to device from *CONTROL socket* with an interval (currently 10 secs), when an operation may take too much time than expected. This prevents unwanted timeouts. When emulator receives **resetTimeout**, countdown and timeout value resets itself. So emulator keeps waiting for dispatcher to complete an operation. Currently this command is sent to emulator in following cases: - Before calculating index - Before preparing zip file to be sent Note that when this message is sent with an interval before a heavy operation, dispatcher must stop sending this message after related operation is complete to prevent sending unnecessary messages to device. ### fileSize ---- ```javascript { "id": "<string: Random GUID>", "command": "fileSize", "data": { "size": "<number>" } } ``` This command is sent to emulator right before sending the file itself. *size* denotes the size of the zip file in terms of bytes. ### start project ---- Received from emulator from *CONTROL* socket, used to start a new debugging session. ### stop project ---- Received from emulator from *CONTROL* socket, used to finalize current debugging session. ### stopDebug ---- ```javascript { "command": "stopDebug" } ``` Received from IDE UI when user presses stop debug button from debugger panel. When this is received, **stop** command is sent to emulator which finalizes debugging process & kills emulator. Then **stop project** is received from emulator. ### cancelTransfer ---- Project checker module runs within CLI right before **getIndex** message is retrieved. When project checker returns with some errors, transfering files to device must be blocked. In order to inform user, **cancelTransfer** message is sent to device over *CONTROL socket* which means a message will be shown on device screen indicating that there are errors must be solved on current workspace. Note that dispatcher can send **cancelTransfer** message with any custom message to be shown on emulator. This message is also used with the development of *IDE Connection Checker*. ### showErrors ---- Works just like *cancelTransfer* message. This message is sent to IDE UI over *UI socket* to inform user from IDE side that there are errors. Errors to be shown are informative enough for user to solve the problems and continue to work. ### - Image Serving When a component with an image source is used with UI-Editor, related image must be rendered correctly. Scaling & rendering image by device information and serving correct image is also performed by dispatcher. Whan a request is made to dispatcher, that request url includes information about image and device. Sample request url: [DISPATCHER_URL]/ui-editor/img/Icon.png?os=iOS&osVersion=10.2&density=326&densityRatio=0.5&zoomLevel=0.37&brandModel=iPhone%207?random=0.40965630020468335 ### - IDE Connection Checker This development is performed due to the requirements specified by Apple AppStore. Updating emulator should not work when IDE is no longer active. This is achieved by storing active project id's inside dispatcher. When UI socket connection is lost, it means connection is lost and updating emulator should not work. In this case user is informed with **cancelTransfer** message with following message: *For security reasons, you cannot update the app while the IDE is closed. To update the app, please start a new session by launching the Cloud IDE and rescanning the new QR code.* This prevents emulator to be updated. ## NOTES - **All** messages are sent to device by 10000B chunks. Which aims the stability of debugger in the first place. Because messages might be too big for v8 to handle. Please refer *src/common/SendChunkedMessage.js* for more information. ## SEQUENCE DIAGRAM ![SEQUENCE DIAGRAM](https://bytebucket.org/smartface-team/ide-dispatcher/raw/e5588ef206bf6f4f0c85b8b909ecd65ea681e128/analysis/dispatcher-sequence-diagram.png?token=51d684fbf89a9d84a4dd0239421059ca6f13ce0f) ## CONNECTIONS ![CONNECTIONS](https://bytebucket.org/smartface-team/ide-dispatcher/raw/526bed98bca0c8bc0957b3648890c701d7d08b37/analysis/connections.png?token=f876fda29572d4afe626e3b24de3d260db0ea658)