recreate backend with lambdas
This commit is contained in:
parent
9de9dcb59b
commit
79b03574ff
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"dotenv.enableAutocloaking": false
|
||||
}
|
||||
@ -8,13 +8,13 @@
|
||||
},
|
||||
"scripts": {
|
||||
"prepare-client-serverless": "bun --filter 'doorman-client' build && cp -fr packages/client/dist/* packages/serverless/assets/ && cp -f packages/serverless/assets/index.html packages/serverless/assets/assets/index.html",
|
||||
"prepare-server-serverless": "bun --filter 'doorman-server' build && cp -fr packages/server/build/* packages/serverless/functions/ && mv packages/serverless/functions/server.js packages/serverless/functions/api.js",
|
||||
"deploy-serverless": "bun run prepare-client-serverless && bun --filter 'serverless' deploy"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/twilio": "^3.19.3",
|
||||
"crypto": "^1.0.1",
|
||||
"express-fingerprint": "^1.2.2",
|
||||
"hono": "^4.3.0",
|
||||
|
||||
@ -28,7 +28,7 @@ export const AuthComponent = ({ door, secret, authMode, onError, onUnlock, runCh
|
||||
}, [runCheck])
|
||||
|
||||
const onSubmit = () => {
|
||||
fetch(`/api/door/${door}/auth?key=${key}&rotatingKey=${key}`)
|
||||
fetch(`/api/door/auth?key=${key}&rotatingKey=${key}&door=${door}`)
|
||||
.then(async res => {
|
||||
if (res.status !== 200) {
|
||||
setError("Incorrect PIN");
|
||||
|
||||
@ -7,7 +7,7 @@ import type { IDoorResponse } from "../../../server/src/types/IDoorResponse";
|
||||
import { CountdownBar } from "../components/CountdownBar";
|
||||
|
||||
export async function loader({ params }: any) {
|
||||
const response = await fetch(params.door ? `/api/door/${params.door}`: `/api/door`).then(res => res.json());
|
||||
const response = await fetch(params.door ? `/api/door/info?door=${params.door}`: `/api/door/info`).then(res => res.json());
|
||||
|
||||
console.log(response);
|
||||
|
||||
@ -74,7 +74,7 @@ export function DoorPage() {
|
||||
}
|
||||
|
||||
const timer = setInterval(async () => {
|
||||
const response = await fetch(`/api/door/${door}`).then(res => res.json());
|
||||
const response = await fetch(`/api/door/info?door=${door}`).then(res => res.json());
|
||||
|
||||
// polling assumes that the door was opened and whatever closed it was the buzzer system...
|
||||
// ie. state transition from OPEN to CLOSED before timeout means that twilio opened the door
|
||||
|
||||
1
packages/serverless/.gitignore
vendored
1
packages/serverless/.gitignore
vendored
@ -11,7 +11,6 @@ lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
assets
|
||||
functions
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
56
packages/serverless/functions/api/door/auth.js
Normal file
56
packages/serverless/functions/api/door/auth.js
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Try to unlock the door with auth mode
|
||||
*/
|
||||
|
||||
const redis = require('redis');
|
||||
|
||||
function doorStatusKey(id) {
|
||||
return concatKeys("doors", id, 'open');
|
||||
}
|
||||
|
||||
function concatKeys(...keys) {
|
||||
return keys.join(':');
|
||||
}
|
||||
|
||||
exports.handler = function(context, event, callback) {
|
||||
const response = new Twilio.Response();
|
||||
|
||||
let door = event.door;
|
||||
let pin = event.key;
|
||||
|
||||
if (!door || !pin) {
|
||||
response.setStatusCode(400);
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
door = door.toUpperCase();
|
||||
|
||||
if (!context['FIXED_PIN_' + door]) {
|
||||
response.setStatusCode(404);
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
let correctPin = context['FIXED_PIN' + door];
|
||||
|
||||
if (correctPin !== pin) {
|
||||
response.setStatusCode(401);
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
let client = new redis.RedisDbClient((err) => console.error(err), { url: context.REDIS_CONNECT_URL });
|
||||
client.connect()
|
||||
.then(async () => {
|
||||
const statusKey = doorStatusKey(door);
|
||||
const fingerprint = { method: "PIN" };
|
||||
const timeout = context['OPEN_TIMEOUT_' + door] || 60;
|
||||
|
||||
await client.put(statusKey, JSON.stringify(fingerprint));
|
||||
await client.getClient().expire(statusKey, timeout);
|
||||
response
|
||||
.setStatusCode(200)
|
||||
.appendHeader('Content-Type', 'application/json')
|
||||
.setBody({ msg: `Opened the door "${door}" for ${timeout}s` });
|
||||
|
||||
return callback(null, response);
|
||||
});
|
||||
};
|
||||
44
packages/serverless/functions/api/door/info.js
Normal file
44
packages/serverless/functions/api/door/info.js
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Try to get door info
|
||||
*/
|
||||
|
||||
const redis = require('redis');
|
||||
|
||||
function doorStatusKey(id) {
|
||||
return concatKeys("doors", id, 'open');
|
||||
}
|
||||
|
||||
function concatKeys(...keys) {
|
||||
return keys.join(':');
|
||||
}
|
||||
|
||||
exports.handler = function(context, event, callback) {
|
||||
const response = new Twilio.Response();
|
||||
|
||||
let door = event.door || context.DEFAULT_DOOR;
|
||||
|
||||
if (!door) {
|
||||
response.setStatusCode(400);
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
door = door.toUpperCase();
|
||||
|
||||
const timeout = context['OPEN_TIMEOUT_' + door] || 60;
|
||||
|
||||
|
||||
res.status(200).json();
|
||||
|
||||
let client = new RedisDbClient((err) => console.error(err), { url: context.REDIS_CONNECT_URL });
|
||||
client.connect()
|
||||
.then(async () => {
|
||||
const status = await client.get(doorStatusKey(door)) ? "OPEN": "CLOSED";
|
||||
|
||||
response
|
||||
.setStatusCode(200)
|
||||
.appendHeader('Content-Type', 'application/json')
|
||||
.setBody({ id: doorId, timeout, status });
|
||||
|
||||
return callback(null, response);
|
||||
});
|
||||
};
|
||||
54
packages/serverless/functions/api/door/status.js
Normal file
54
packages/serverless/functions/api/door/status.js
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Try to update door status
|
||||
*/
|
||||
|
||||
const redis = require('redis');
|
||||
|
||||
function doorStatusKey(id) {
|
||||
return concatKeys("doors", id, 'open');
|
||||
}
|
||||
|
||||
function concatKeys(...keys) {
|
||||
return keys.join(':');
|
||||
}
|
||||
|
||||
exports.handler = function(context, event, callback) {
|
||||
const response = new Twilio.Response();
|
||||
|
||||
let door = event.door;
|
||||
|
||||
if (!door) {
|
||||
response.setStatusCode(400);
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
let client = new RedisDbClient((err) => console.error(err), { url: context.REDIS_CONNECT_URL });
|
||||
client.connect()
|
||||
.then(async () => {
|
||||
const isOpen = await client.get(doorStatusKey(door));
|
||||
|
||||
if (isOpen) {
|
||||
const fingerprint = JSON.parse(isOpen);
|
||||
|
||||
response
|
||||
.setStatusCode(200)
|
||||
.appendHeader('Content-Type', 'application/json')
|
||||
.setBody({
|
||||
status: "OPEN",
|
||||
fingerprint,
|
||||
});
|
||||
await client.remove(doorStatusKey(req.params.id));
|
||||
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
response
|
||||
.setStatusCode(401)
|
||||
.appendHeader('Content-Type', 'application/json')
|
||||
.setBody({
|
||||
status: "CLOSED",
|
||||
});
|
||||
|
||||
return callback(null, response);
|
||||
});
|
||||
};
|
||||
@ -11,10 +11,6 @@
|
||||
"dependencies": {
|
||||
"twilio": "^3.56",
|
||||
"@twilio/runtime-handler": "1.3.0",
|
||||
"@codegenie/serverless-express": "^4.14.1",
|
||||
"express": "^4.18.2",
|
||||
"express-fileupload": "^1.4.0",
|
||||
"express-rate-limit": "^6.10.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"redis": "^4.6.8"
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user