mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 07:04:52 +09:00
Refine the state flow used in the connector abstractions to better handle close while connecting and resuming. The new logic is to close the connection immediately in these two states instead of continuing trying to connect and then giving up some point later. For the connectors the handshake state is split into connecting and resuming, new is replaced by closed, and the closing state is turned into a boolean flag as it's possible that closing is desired while connecting, connected or resuming. The connecting state is not present in the server connector because there's nothing for the server to do in that connector state. The timeout logic is completely removed, once a connection attempt is started for the client it will continue to attempt to connect, attempt to resume dropped connections and attempt reconnects until either an authentication error occurs or the client explicitly requests to close the connection. A new session timeout is added to control how long to attempt to resume the connection until it's considered dead and invalidated. This allows stale connections to give up earlier, and swallow up less data while in the dropped but not yet invalidated state. For the client side sending messages while it's connecting has been changed to throw an error instead of queuing up the message and (possibly) sending it after the connection is established. Code shouldn't try to send messages without knowing if the connection it's trying to send them over is active or not.
218 lines
4.9 KiB
JavaScript
218 lines
4.9 KiB
JavaScript
/**
|
|
* JSON schemas used for validating link messages
|
|
* @module lib/schema
|
|
*/
|
|
"use strict";
|
|
const Ajv = require("ajv");
|
|
const ajv = new Ajv({
|
|
verbose: true,
|
|
format: "full",
|
|
extendRefs: "fail",
|
|
strictDefaluts: true,
|
|
strictKeywords: true,
|
|
});
|
|
|
|
|
|
/**
|
|
* The base format for any message sent over the link
|
|
*/
|
|
const messageSchema = {
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
title: "Message",
|
|
description: "Format for messages on a link",
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["seq", "type", "data"],
|
|
properties: {
|
|
"seq": { type: ["integer", "null"] },
|
|
"type": { type: "string" },
|
|
"data": { type: "object" },
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Validator for message schemas
|
|
* @function
|
|
* @param {Object} obj - Object to validate
|
|
* @returns {boolean} True if object passed validation.
|
|
*/
|
|
const message = ajv.compile(messageSchema);
|
|
|
|
/**
|
|
* Validator for heartbeat messages
|
|
* @function
|
|
* @param {Object} obj - Object to validate
|
|
* @returns {boolean} True if object passed validation.
|
|
*/
|
|
const heartbeat = ajv.compile({
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
title: "Heartbeat",
|
|
description: "Heartbeat sent over link",
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["seq", "type", "data"],
|
|
properties: {
|
|
"seq": { const: null },
|
|
"type": { const: "heartbeat" },
|
|
"data": {
|
|
type: "object",
|
|
additionalProperties: false,
|
|
required: ["seq"],
|
|
properties: {
|
|
"seq": { type: ["integer", "null"] },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Validator for server sent part of handshake
|
|
* @function
|
|
* @param {Object} obj - Object to validate
|
|
* @returns {boolean} True if object passed validation.
|
|
*/
|
|
const serverHandshake = ajv.compile({
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
title: "Server Handshake",
|
|
description: "Message sent from the server to a client during the handshake",
|
|
allOf: [messageSchema],
|
|
anyOf: [
|
|
{
|
|
properties: {
|
|
"type": { const: "hello" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["version", "plugins"],
|
|
properties: {
|
|
"version": { type: "string" },
|
|
"plugins": {
|
|
type: "object",
|
|
additionalProperties: { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
properties: {
|
|
"type": { const: "ready" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["session_token", "session_timeout", "heartbeat_interval"],
|
|
properties: {
|
|
"session_token": { type: "string" },
|
|
"session_timeout": { type: "number" },
|
|
"heartbeat_interval": { type: "number" },
|
|
"account": {
|
|
additionalProperties: false,
|
|
required: ["name"],
|
|
properties: {
|
|
"name": { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
properties: {
|
|
"type": { const: "continue" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["last_seq", "session_timeout", "heartbeat_interval"],
|
|
properties: {
|
|
"last_seq": { type: ["integer", "null"] },
|
|
"session_timeout": { type: "number" },
|
|
"heartbeat_interval": { type: "number" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
properties: {
|
|
"type": { const: "invalidate" },
|
|
"data": { const: {} },
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
/**
|
|
* Validator for client sent part of handshake
|
|
* @function
|
|
* @param {Object} obj - Object to validate
|
|
* @returns {boolean} True if object passed validation.
|
|
*/
|
|
const clientHandshake = ajv.compile({
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
title: "Client Message",
|
|
description: "Message sent from a client to the server",
|
|
allOf: [messageSchema],
|
|
anyOf: [
|
|
{
|
|
properties: {
|
|
"type": { const: "register_slave" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["token", "agent", "version", "name", "id", "plugins"],
|
|
properties: {
|
|
"token": { type: "string" },
|
|
"agent": { type: "string" },
|
|
"version": { type: "string" },
|
|
"name": { type: "string" },
|
|
"id": { type: "integer" },
|
|
"plugins": {
|
|
type: "object",
|
|
additionalProperties: { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
properties: {
|
|
"type": { const: "register_control" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["token", "agent", "version"],
|
|
properties: {
|
|
"token": { type: "string" },
|
|
"agent": { type: "string" },
|
|
"version": { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
properties: {
|
|
"type": { const: "resume" },
|
|
"data": {
|
|
additionalProperties: false,
|
|
required: ["session_token", "last_seq"],
|
|
properties: {
|
|
"session_token": { type: "string" },
|
|
"last_seq": { type: ["integer", "null"] },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
|
|
module.exports = {
|
|
/**
|
|
* Compile JSON schema into validator
|
|
* @function
|
|
* @param {Object} schema - JSON schema to create validator for.
|
|
* @returns {Function} Validator for the schema.
|
|
*/
|
|
compile: ajv.compile.bind(ajv),
|
|
|
|
message,
|
|
heartbeat,
|
|
|
|
serverHandshake,
|
|
clientHandshake,
|
|
};
|