Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service Work Sample #544

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions lib/browser/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

import buffer from 'buffer';
import process from 'process';

// Workaround to get mqtt-js working with Webpack 5
if (window) {
(window as any).Buffer = buffer.Buffer;
(window as any).process = process;
// NodeJS global shim workaround for Angular
(window as any).global = window;
if (typeof self !== 'undefined') {
(self as any).Buffer = buffer.Buffer;
(self as any).process = process;

if (self.window) {
// NodeJS global shim workaround for Angular
(self.window as any).global = window
}
}

export {};
18 changes: 18 additions & 0 deletions samples/browser/service_worker/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist','.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
19 changes: 19 additions & 0 deletions samples/browser/service_worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Service Worker

The sample is a quick demonstration for setup service worker with aws-crt library. The sample would setup an mqtt5 client on service worker installed, and publish a message on service worker "message" event.
The sample would not be maintained until aws-crt claim full support for service worker.

## Setup
0. Install SDK, then change folder to `./samples/browser/service_worker`
1. run `yarn`
2. run `yarn dev`, open another terminal and run `yarn vite -c vite.config.sw.ts build --watch` which will build the service worker in watch mode
3. Load [localhost:3030](http://localhost:3030)
4. Open browser's DevTools/console to track client messages

### Important Note On Testing Service Workers
ServiceWorkers are designed to live for a long time and be available offline. As such, the caching policies around them are very aggressive, by design. To help with development it is highly recommended to enable "Update on reload" in Chrome dev tools.

1. Open DevTools
2. Navigate to the _Application_ tab
3. On the left navigation within Application click _Service workers_
4. Toggle "Update on reload"
12 changes: 12 additions & 0 deletions samples/browser/service_worker/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>IOT SDK -- Service Worker</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions samples/browser/service_worker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "iotserviceworker",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"aws-crt": "file:../../../",
"events": "^3.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"typescript": "^5.2.2",
"vite": "^5.1.6"
}
}
39 changes: 39 additions & 0 deletions samples/browser/service_worker/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect } from "react";

function App() {
useEffect(() => {
let registration: ServiceWorkerRegistration | undefined;
async function registerServiceWorker() {
// Register service worker
navigator.serviceWorker.register("./service-worker.js");

// Get registration
registration = await navigator.serviceWorker.ready;
const worker = registration.active;
if (worker) {
worker.postMessage(
"This message will trigger the 'message' in the service worker"
);
}
}
// Clean up the service worker before register the new one
navigator.serviceWorker.getRegistrations().then(registrations => {
for (const registration of registrations) {
registration.unregister();
}
});
registerServiceWorker();

return () => {
registration?.unregister();
};
}, []);

return (
<>
<div>Please checkout the "Developer Tools" for console messages.</div>
</>
);
}

export default App;
4 changes: 4 additions & 0 deletions samples/browser/service_worker/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const AUTHORIZER_NAME = "'<your authorizer name>";
export const USERNAME = '<your user name>';
export const PASSWORD = '<your password>';
export const AWS_IOT_ENDPOINT = '<your endpoint>';
9 changes: 9 additions & 0 deletions samples/browser/service_worker/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
77 changes: 77 additions & 0 deletions samples/browser/service_worker/src/pub_sub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

import {mqtt5, auth, iot, MqttConnectCustomAuthConfig} from "aws-crt"
import {once} from "events"
import * as settings from "./config"
import { toUtf8 } from '@aws-sdk/util-utf8-browser';
/// @ts-ignore

let client : mqtt5.Mqtt5Client | undefined = undefined
const test_topic = "hello/world/qos0"

function createClient() : mqtt5.Mqtt5Client {

let customAuthConfig : MqttConnectCustomAuthConfig = {
authorizerName: settings.AUTHORIZER_NAME,
username: settings.USERNAME,
password: settings.PASSWORD
};

let builder = iot.AwsIotMqtt5ClientConfigBuilder.newWebsocketMqttBuilderWithCustomAuth(
settings.AWS_IOT_ENDPOINT,
customAuthConfig
);

console.log("Connecting custom authorizer...");
client = new mqtt5.Mqtt5Client(builder.build());
client.on("messageReceived",(eventData: mqtt5.MessageReceivedEvent) : void => {
console.log("Message Received event: " + JSON.stringify(eventData.message));
if (eventData.message.payload) {
console.log(" with payload: " + toUtf8(new Uint8Array(eventData.message.payload as ArrayBuffer)));
}
} );

return client;
}

export async function setupConnection() {

if(client != undefined) return;
/** Set up the credentialsProvider */
client = createClient();

const attemptingConnect = once(client, "attemptingConnect");
const connectionSuccess = once(client, "connectionSuccess");

client.start();

await attemptingConnect;
await connectionSuccess;

const suback = await client.subscribe({
subscriptions: [
{ qos: mqtt5.QoS.AtLeastOnce, topicFilter: test_topic }
]
});
console.log('Suback result: ' + JSON.stringify(suback));
}

export async function Mqtt5ClientPublish()
{
await setupConnection()
if (!client)
{
console.log("[Warning] Client has not been setup.")
return
}
const qos0PublishResult = await client.publish({
qos: mqtt5.QoS.AtLeastOnce,
topicName: test_topic,
payload: "This is a qos 1 payload"
});
console.log('QoS 1 Publish result: ' + JSON.stringify(qos0PublishResult));
}

20 changes: 20 additions & 0 deletions samples/browser/service_worker/src/service-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// <reference no-default-lib="true"/>
/// <reference lib="es2015" />
/// <reference lib="webworker" />

import { mqtt} from "aws-crt";
import { setupConnection, Mqtt5ClientPublish } from "./pub_sub";

addEventListener("install", async (event) => {
console.log(`Service Worker Install: ${event.data}`);
console.log(`Setup mqtt client`)
await setupConnection()
});

addEventListener("message", async (event) => {
console.log(`Message Received: ${event.data}`);
await Mqtt5ClientPublish()
console.log("Finish Publish Message")
});


1 change: 1 addition & 0 deletions samples/browser/service_worker/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
27 changes: 27 additions & 0 deletions samples/browser/service_worker/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"paths": {
"aws-crt": ["./node_modules/aws-crt/dist.browser/browser"]
},
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
11 changes: 11 additions & 0 deletions samples/browser/service_worker/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}
15 changes: 15 additions & 0 deletions samples/browser/service_worker/vite.config.sw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
build: {
outDir: 'public',
minify: false,
lib: {
entry: 'src/service-worker.ts',
name: "service-worker",
formats: ["es"],
fileName: () => "service-worker.js"
}
}
})
10 changes: 10 additions & 0 deletions samples/browser/service_worker/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 3030,
},
plugins: [react()],
})
Loading