|
| 1 | +--- |
| 2 | +title: Implementation Guide |
| 3 | +--- |
| 4 | + |
| 5 | +# Messaging Implementation Guide |
| 6 | + |
| 7 | +## Step 1) Receiving a notification or request message: |
| 8 | + |
| 9 | +Each platform will 'receive' messages according to their own best practices, the following spec describes everything **after** |
| 10 | +the message has been delivered from the clientside JavaScript (deliberately avoiding the platform specifics of *how* messages arrive) |
| 11 | + |
| 12 | +For example, in Android this would be what happens within a `@Javascript` Interface, but on macOS it would be within |
| 13 | +the WebKit messaging protocol, etc. |
| 14 | + |
| 15 | +### Algorithm |
| 16 | + |
| 17 | +1. let `s` be an incoming raw `JSON` payload |
| 18 | +2. let `msg` be the result of parsing `s` into key/value pairs |
| 19 | + - 2.1 Note: 'parsing' here may not be required if the platform in question receives JSON data directly (ie: JavaScript environments) |
| 20 | +3. if parsing was not successful, log an "invalid message" exception and exit. |
| 21 | +4. validate that `msg.context` exists and is a `string` value |
| 22 | +5. validate that `msg.featureName` exists and is a `string` value |
| 23 | +6. validate that `msg.method` exists and is a `string` value |
| 24 | + - 6.1 if `context`, `featureName` or `method` are invalid (not a string, or missing), log an "invalid message" Exception and exit. |
| 25 | +7. let `params` be a reference to `msg.params` or a new, empty key/value structure |
| 26 | +8. if `params` is not a valid key/value structure, log an "invalid params" exception and exit. |
| 27 | +9. if the `msg.id` field is absent, then: |
| 28 | + - 9.1. mark `msg` as being of type {@link Messaging.NotificationMessage} |
| 29 | +10. if the `msg.id` field is present, then: |
| 30 | + - 10.1. validate that `msg.id` a string value, log an "invalid id" exception if it isn't, and exit. |
| 31 | + - 10.2. mark `msg` as being of type {@link Messaging.RequestMessage} |
| 32 | +11. At this point, you should have a structure that represents either a {@link Messaging.NotificationMessage} or |
| 33 | + {@link Messaging.RequestMessage}. Then move to Step 2) |
| 34 | + |
| 35 | + |
| 36 | +## Step 2) Choosing and executing a handler |
| 37 | + |
| 38 | +Once you've completed Step 1), you'll know whether you are dealing with a notification or a request (something you need |
| 39 | +to respond to). At this point you don't know which feature will attempt the message, you just know the format was correct. |
| 40 | + |
| 41 | +### Algorithm |
| 42 | + |
| 43 | +1. let `feature` be the result of looking up a feature that matches name `msg.featureName` |
| 44 | +2. if `feature` is not found: |
| 45 | + - 2.1 if `msg` was marked as type `Request`, return a "feature not found" [Error Response](./examples.md#error-response) |
| 46 | + - 2.2 if `msg` was marked as type `Notification`, optionally log a "feature not found" exception and exit |
| 47 | +3. let `handler` be the result of calling `feature.handlerFor(msg.method)` |
| 48 | +4. if `handler` is not found: |
| 49 | + - 4.1 if `msg` was marked as type `Request`, return a "method not found" [Error Response](./examples.md#error-response) |
| 50 | + - 4.2 if `msg` was marked as type `Notification`, optionally log a "feature not found" exception and exit |
| 51 | +5. execute `handler` with `msg.params` |
| 52 | + - 5.1. if `msg` was marked as a {@link Messaging.NotificationMessage} (via step 1), then: |
| 53 | + 1. do not wait for a response |
| 54 | + 2. if the platform must respond (to prevent errors), then: |
| 55 | + 1. respond with an empty key/value JSON structure `{}` |
| 56 | + - 5.2. if `msg` was marked as a {@link Messaging.RequestMessage}, then: |
| 57 | + 1. let `response` be a new instance of {@link Messaging.MessageResponse} |
| 58 | + 1. assign `msg.context` to `response.context` |
| 59 | + 2. assign `msg.featureName` to `response.featureName` |
| 60 | + 3. assign `msg.id` to `response.id` |
| 61 | + 2. let `result` be the return value of _executing_ `handler(msg.params)` |
| 62 | + 3. if `result` is empty, assign `result` to an empty key/value structure |
| 63 | + 4. if an **error** occurred during execution, then: |
| 64 | + 1. let `error` be a new instance of {@link Messaging.MessageError} |
| 65 | + 2. assign a descriptive message if possible, to `error.message` |
| 66 | + 3. assign `error` to `response.error` |
| 67 | + 5. if an error **did not occur**, assign `result` to `response.result` |
| 68 | + 6. let `json` be the string result of converting `response` into JSON |
| 69 | + 7. deliver the JSON response in the platform-specified way |
| 70 | + |
| 71 | +## Step 3) Push-based messaging |
| 72 | + |
| 73 | +1. let `event` be a new instance of {@link Messaging.SubscriptionEvent} |
| 74 | +2. assign `event.context` to the target context |
| 75 | +3. assign `event.featureName` to the target feature |
| 76 | +4. assign `event.subscriptionName` to the target subscriptionName |
| 77 | +5. if the message contains data, then |
| 78 | + 1. let `params` be a key/value structure |
| 79 | + 1. Note: only key/value structures are permitted. |
| 80 | + 2. assign `params` to `event.params` |
| 81 | +6. let `json` be the string result of converting `event` into JSON |
| 82 | +7. deliver the JSON response in the platform-specified way |
0 commit comments