JavaScript Functions quickstart - ready for review (#267)
* first pass * edits * fixes * 2 folders * Update signalr client lib
This commit is contained in:
Родитель
74df6bd4fb
Коммит
022f453f81
|
@ -0,0 +1,10 @@
|
|||
*.js.map
|
||||
*.ts
|
||||
.git*
|
||||
.vscode
|
||||
__azurite_db*__.json
|
||||
__blobstorage__
|
||||
__queuestorage__
|
||||
local.settings.json
|
||||
test
|
||||
tsconfig.json
|
100
samples/QuickStartServerless/javascript/v4-programming-model/.gitignore
поставляемый
Normal file
100
samples/QuickStartServerless/javascript/v4-programming-model/.gitignore
поставляемый
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TypeScript output
|
||||
dist
|
||||
out
|
||||
|
||||
# Azure Functions artifacts
|
||||
bin
|
||||
obj
|
||||
appsettings.json
|
||||
local.settings.json
|
||||
|
||||
# Azurite artifacts
|
||||
**/__azurite__
|
||||
__blobstorage__
|
||||
__queuestorage__
|
||||
__azurite_db*__.json
|
|
@ -0,0 +1,38 @@
|
|||
# SignalR Service Serverless Quick Start (JavaScript)
|
||||
|
||||
In this sample, we demonstrate how to broadcast messages with SignalR Service and Azure Function in serverless.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Azure Function Core Tools](https://www.npmjs.com/package/azure-functions-core-tools)
|
||||
* [Node.js LTS](https://nodejs.org/en/download/)
|
||||
|
||||
## Azure Functions with CommonJS
|
||||
|
||||
Because ESM support is still in [preview for Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-reference-node?tabs=javascript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#ecmascript-modules), this quickstart uses CommonJS modules including node-fetch. If you update the node-fetch package to 3.x, you may need to update the code to use ESM modules, which requires changing from `const` to `import` and `*.js` to `*.mjs`.
|
||||
|
||||
## Setup and run locally
|
||||
|
||||
1. Start local storage emulator in terminal.
|
||||
|
||||
```bash
|
||||
npm run start:azurite
|
||||
```
|
||||
|
||||
1. Rename `local.settings.template.json` to `local.settings.json` and update env variable.
|
||||
|
||||
* `SIGNALR_CONNECTION_STRING`: The connection string of your Azure SignalR Service.
|
||||
|
||||
1. Run command to start Azure Function locally in different terminal.
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
1. Visit `http://localhost:7071/api/index`.
|
||||
|
||||
![Screenshot of index showing no star count](./media/screenshot-index.png)
|
||||
|
||||
1. Go to this repo's home page and click the star button to increase or decrease the star count.
|
||||
|
||||
1. The Azure Functions **broadcast** function is triggered every minute to see if the star count has changed. If it has chanaged base on checking the eTag, a new star count is sent as a message to the client.
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": "2.0",
|
||||
"logging": {
|
||||
"applicationInsights": {
|
||||
"samplingSettings": {
|
||||
"isEnabled": true,
|
||||
"excludedTypes": "Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extensionBundle": {
|
||||
"id": "Microsoft.Azure.Functions.ExtensionBundle",
|
||||
"version": "[4.*, 5.0.0)"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "node",
|
||||
"AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
|
||||
"SIGNALR_CONNECTION_STRING": "<SIGNALR_CONNECTION_STRING>"
|
||||
}
|
||||
}
|
Двоичные данные
samples/QuickStartServerless/javascript/v4-programming-model/media/screenshot-index.png
Normal file
Двоичные данные
samples/QuickStartServerless/javascript/v4-programming-model/media/screenshot-index.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 30 KiB |
4082
samples/QuickStartServerless/javascript/v4-programming-model/package-lock.json
сгенерированный
Normal file
4082
samples/QuickStartServerless/javascript/v4-programming-model/package-lock.json
сгенерированный
Normal file
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "javascript",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"start:azurite": "azurite -s -l __azurite__",
|
||||
"start": "func start",
|
||||
"test": "echo \"No tests yet...\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/functions": "^4.0.0",
|
||||
"node-fetch": "2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"azurite": "3.29.0",
|
||||
"azure-functions-core-tools": "^4.0.5611"
|
||||
},
|
||||
"main": "src/functions/*.js"
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<html>
|
||||
|
||||
<body>
|
||||
<h1>Azure SignalR Serverless Sample</h1>
|
||||
<div>Instructions: Goto <a href="https://github.com/Azure/azure-signalr">GitHub repo</a> and star the repository.</div>
|
||||
<hr>
|
||||
<div>Star count: <div id="messages"></div></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script>
|
||||
<script>
|
||||
let messages = document.querySelector('#messages');
|
||||
const apiBaseUrl = window.location.origin;
|
||||
console.log(`apiBaseUrl: ${apiBaseUrl}`);
|
||||
const connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl(apiBaseUrl + '/api')
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.build();
|
||||
connection.on('newMessage', (message) => {
|
||||
console.log(`message: ${message}`);
|
||||
document.getElementById("messages").innerHTML = message;
|
||||
});
|
||||
|
||||
connection.start()
|
||||
.catch(console.error);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,40 @@
|
|||
const { app, output } = require('@azure/functions');
|
||||
const getStars = require('../getStars');
|
||||
|
||||
var etag = '';
|
||||
var star = 0;
|
||||
|
||||
const goingOutToSignalR = output.generic({
|
||||
type: 'signalR',
|
||||
name: 'signalR',
|
||||
hubName: 'serverless',
|
||||
connectionStringSetting: 'SIGNALR_CONNECTION_STRING',
|
||||
});
|
||||
|
||||
app.timer('sendMessasge', {
|
||||
schedule: '0 * * * * *',
|
||||
extraOutputs: [goingOutToSignalR],
|
||||
handler: async (myTimer, context) => {
|
||||
|
||||
try {
|
||||
const response = await getStars(etag);
|
||||
|
||||
if(response.etag === etag){
|
||||
console.log(`Same etag: ${response.etag}, no need to broadcast message`);
|
||||
return;
|
||||
}
|
||||
|
||||
etag = response.etag;
|
||||
const message = `${response.stars}`;
|
||||
|
||||
context.extraOutputs.set(goingOutToSignalR,
|
||||
{
|
||||
'target': 'newMessage',
|
||||
'arguments': [message]
|
||||
});
|
||||
} catch (error) {
|
||||
context.log(error);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
const { app } = require('@azure/functions');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
app.http('index', {
|
||||
methods: ['GET', 'POST'],
|
||||
authLevel: 'anonymous',
|
||||
handler: async (request, context) => {
|
||||
|
||||
try {
|
||||
|
||||
context.log(`Http function processed request for url "${request.url}"`);
|
||||
|
||||
const filePath = path.join(__dirname,'../content/index.html');
|
||||
const html = await fs.readFile(filePath);
|
||||
|
||||
return {
|
||||
body: html,
|
||||
headers: {
|
||||
'Content-Type': 'text/html'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
context.log(error);
|
||||
return {
|
||||
status: 500,
|
||||
jsonBody: error
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
const { app, input } = require('@azure/functions');
|
||||
|
||||
const inputSignalR = input.generic({
|
||||
type: 'signalRConnectionInfo',
|
||||
name: 'connectionInfo',
|
||||
hubName: 'serverless',
|
||||
connectionStringSetting: 'SIGNALR_CONNECTION_STRING',
|
||||
});
|
||||
|
||||
app.post('negotiate', {
|
||||
authLevel: 'anonymous',
|
||||
handler: (request, context) => {
|
||||
try {
|
||||
return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) }
|
||||
} catch (error) {
|
||||
context.log(error);
|
||||
return {
|
||||
status: 500,
|
||||
jsonBody: error
|
||||
}
|
||||
}
|
||||
},
|
||||
route: 'negotiate',
|
||||
extraInputs: [inputSignalR],
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
const fetch = require('node-fetch');
|
||||
|
||||
const URL = "https://api.github.com/repos/azure/azure-signalr"
|
||||
|
||||
async function getStars(currentEtag){
|
||||
|
||||
console.log(`currentEtag: ${currentEtag}`);
|
||||
const headers = {
|
||||
'If-None-Match': currentEtag
|
||||
};
|
||||
|
||||
const response = await fetch(URL, { headers });
|
||||
if(response.ok){
|
||||
|
||||
const etag = response.headers.get('etag');
|
||||
const { stargazers_count } = await response.json();
|
||||
|
||||
console.log(`Current star count is: ${stargazers_count}`);
|
||||
|
||||
return { etag, stars: stargazers_count };
|
||||
} else {
|
||||
console.log('Failed to fetch data: ' + response.status + ' ' + response.statusText);
|
||||
return { etag: currentEtag, stars: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getStars;
|
Загрузка…
Ссылка в новой задаче