Skip to content

Commit

Permalink
fixup! refactor(coap-server): refactor handleRequest method
Browse files Browse the repository at this point in the history
  • Loading branch information
JKRhb committed Jul 20, 2023
1 parent f47db7e commit 0d7c6de
Showing 1 changed file with 143 additions and 147 deletions.
290 changes: 143 additions & 147 deletions packages/binding-coap/src/coap-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,157 +456,16 @@ export default class CoapServer implements ProtocolServer {
case this.PROPERTY_DIR:
this.handlePropertyRequest(thing, affordanceKey, req, res, contentType);
return;
}

if (affordanceType === this.ACTION_DIR) {
// sub-path -> select Action
const action = thing.actions[affordanceKey];

if (action == null) {
case this.ACTION_DIR:
this.handleActionRequest(thing, affordanceKey, req, res, contentType);
return;
}

// invokeaction
if (req.method === "POST") {
const options: WoT.InteractionOptions & { formIndex: number } = {
formIndex: ProtocolHelpers.findRequestMatchingFormIndex(
action.forms,
this.scheme,
req.url,
contentType
),
};
const uriVariables = Helpers.parseUrlParameters(req.url, thing.uriVariables, action.uriVariables);
if (!this.isEmpty(uriVariables)) {
options.uriVariables = uriVariables;
}
try {
const output = await thing.handleInvokeAction(
affordanceKey,
new Content(contentType, Readable.from(req.payload)),
options
);
if (output) {
res.setOption("Content-Format", output.type);
res.code = "2.05";
output.body.pipe(res, { end: true });
} else {
res.code = "2.04";
res.end();
}
} catch (err) {
error(
`CoapServer on port ${this.getPort()} got internal error on invoke '${requestUri}': ${
err.message
}`
);
res.code = "5.00";
res.end(err.message);
}
} else {
res.code = "4.05";
res.end("Method Not Allowed");
}
} else if (affordanceType === this.EVENT_DIR) {
// sub-path -> select Event
const event = thing.events[affordanceKey];

if (event == null) {
case this.EVENT_DIR:
this.handleEventRequest(thing, affordanceKey, req, res, contentType);
return;
}

// subscribeevent
if (req.method === "GET") {
if (req.headers.Observe === 0) {
// work-around to avoid duplicate requests (resend due to no response)
// (node-coap does not deduplicate when Observe is set)
const packet = res._packet;
packet.code = "0.00";
packet.payload = Buffer.from("");
packet.reset = false;
packet.ack = true;
packet.token = Buffer.alloc(0);

res._send(res, packet);

res._packet.confirmable = res._request.confirmable;
res._packet.token = res._request.token;
// end of work-around

const options: WoT.InteractionOptions & { formIndex: number } = {
formIndex: ProtocolHelpers.findRequestMatchingFormIndex(
event.forms,
this.scheme,
req.url,
contentType
),
};
const uriVariables = Helpers.parseUrlParameters(
req.url,
thing.uriVariables,
event.uriVariables
);
if (!this.isEmpty(uriVariables)) {
options.uriVariables = uriVariables;
}
const listener = async (value: Content) => {
try {
// send event data
debug(
`CoapServer on port ${this.getPort()} sends '${affordanceKey}' notification to ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
res.setOption("Content-Format", value.type);
res.code = "2.05";
value.body.pipe(res);
} catch (err) {
debug(`CoapServer on port ${this.getPort()} failed '${affordanceKey}' subscription`);
res.code = "5.00";
res.end();
}
};

thing
.handleSubscribeEvent(affordanceKey, listener, options)
.then(() => res.end())
.catch(() => res.end());
res.on("finish", () => {
debug(
`CoapServer on port ${this.getPort()} ends '${affordanceKey}' observation from ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
thing.handleUnsubscribeEvent(affordanceKey, listener, options);
});
} else if (req.headers.Observe > 0) {
debug(
`CoapServer on port ${this.getPort()} sends '${affordanceKey}' response to ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
// node-coap does not support GET cancellation
res.code = "5.01";
res.end("node-coap issue: no GET cancellation, send RST");
} else {
debug(
`CoapServer on port ${this.getPort()} rejects '${affordanceKey}' read from ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
res.code = "4.00";
res.end("No Observe Option");
}
} else {
res.code = "4.05";
res.end("Method Not Allowed");
}
}
}

// resource not found
res.code = "4.04";
res.end("Not Found");
this.sendErrorResponse(res, "4.04", "Resource not found");
}

private async handlePropertyRequest(
Expand Down Expand Up @@ -741,8 +600,145 @@ export default class CoapServer implements ProtocolServer {
}
}

private async handleActionRequest(
thing: ExposedThing,
affordanceKey: string,
req: IncomingMessage,
res: OutgoingMessage,
contentType: string
) {
const action = thing.actions[affordanceKey];

if (action == null) {
return;
}

if (req.method !== "POST") {
this.sendErrorResponse(res, "4.05", "Method Not Allowed");
return;
}

const options: WoT.InteractionOptions & { formIndex: number } = {
formIndex: ProtocolHelpers.findRequestMatchingFormIndex(action.forms, this.scheme, req.url, contentType),
};
const uriVariables = Helpers.parseUrlParameters(req.url, thing.uriVariables, action.uriVariables);
if (!this.isEmpty(uriVariables)) {
options.uriVariables = uriVariables;
}
try {
const output = await thing.handleInvokeAction(
affordanceKey,
new Content(contentType, Readable.from(req.payload)),
options
);
if (output) {
res.setOption("Content-Format", output.type);
res.code = "2.05";
output.body.pipe(res, { end: true });
} else {
res.code = "2.04";
res.end();
}
} catch (err) {
error(`CoapServer on port ${this.getPort()} got internal error on invoke '${req.url}': ${err.message}`);
this.sendErrorResponse(res, "5.00", err.message);
}
}

private async handleEventRequest(
thing: ExposedThing,
affordanceKey: string,
req: IncomingMessage,
res: OutgoingMessage,
contentType: string
) {
// sub-path -> select Event
const event = thing.events[affordanceKey];

if (event == null) {
return;
}

if (req.method !== "GET") {
this.sendErrorResponse(res, "4.05", "Method Not Allowed");
return;
}

// subscribeevent
if (req.headers.Observe === 0) {
// work-around to avoid duplicate requests (resend due to no response)
// (node-coap does not deduplicate when Observe is set)
const packet = res._packet;
packet.code = "0.00";
packet.payload = Buffer.from("");
packet.reset = false;
packet.ack = true;
packet.token = Buffer.alloc(0);

res._send(res, packet);

res._packet.confirmable = res._request.confirmable;
res._packet.token = res._request.token;
// end of work-around

const options: WoT.InteractionOptions & { formIndex: number } = {
formIndex: ProtocolHelpers.findRequestMatchingFormIndex(event.forms, this.scheme, req.url, contentType),
};
const uriVariables = Helpers.parseUrlParameters(req.url, thing.uriVariables, event.uriVariables);
if (!this.isEmpty(uriVariables)) {
options.uriVariables = uriVariables;
}
const listener = async (value: Content) => {
try {
// send event data
debug(
`CoapServer on port ${this.getPort()} sends '${affordanceKey}' notification to ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
res.setOption("Content-Format", value.type);
res.code = "2.05";
value.body.pipe(res);
} catch (err) {
debug(`CoapServer on port ${this.getPort()} failed '${affordanceKey}' subscription`);
this.sendErrorResponse(res, "5.00", `Subscription to event failed`);
}
};

thing
.handleSubscribeEvent(affordanceKey, listener, options)
.then(() => res.end())
.catch(() => res.end());
res.on("finish", () => {
debug(
`CoapServer on port ${this.getPort()} ends '${affordanceKey}' observation from ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
thing.handleUnsubscribeEvent(affordanceKey, listener, options);
});
} else if (req.headers.Observe > 0) {
debug(
`CoapServer on port ${this.getPort()} sends '${affordanceKey}' response to ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
// TODO: Check if this has been fixed in the meantime
// node-coap does not support GET cancellation
this.sendErrorResponse(res, "5.01", "node-coap issue: no GET cancellation, send RST");
} else {
debug(
`CoapServer on port ${this.getPort()} rejects '${affordanceKey}' read from ${Helpers.toUriLiteral(
req.rsinfo.address
)}:${req.rsinfo.port}`
);
res.code = "4.00";
res.end("No Observe Option");
}
}

private sendErrorResponse(res: OutgoingMessage, errorCode: string, errorMessage: string) {
res.code = "5.00";
res.code = errorCode;
res.end(errorMessage);
}

Expand Down

0 comments on commit 0d7c6de

Please sign in to comment.