Не удалось использовать apigwManagementApi.postToConnection в маршруте $ connect - PullRequest
2 голосов
/ 15 апреля 2019

Я хочу вернуть connectionId клиенту после того, как клиент подключился к веб-сокету aws.

Я использую apigwManagementApi.postToConnection для отправки ответа клиенту, но я всегда получаю абсурдное сообщение об ошибке.

Я уже пытаюсь отладить и выполнить поиск в Google, но я не могу 't найти решение для этого.

patch.js

require('aws-sdk/lib/node_loader');
var AWS = require('aws-sdk/lib/core');
var Service = AWS.Service;
var apiLoader = AWS.apiLoader;

apiLoader.services['apigatewaymanagementapi'] = {};
AWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29']);
Object.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', {
  get: function get() {
    var model = {
      "metadata": {
        "apiVersion": "2018-11-29",
        "endpointPrefix": "execute-api",
        "signingName": "execute-api",
        "serviceFullName": "AmazonApiGatewayManagementApi",
        "serviceId": "ApiGatewayManagementApi",
        "protocol": "rest-json",
        "jsonVersion": "1.1",
        "uid": "apigatewaymanagementapi-2018-11-29",
        "signatureVersion": "v4"
      },
      "operations": {
        "PostToConnection": {
          "http": {
            "requestUri": "/@connections/{connectionId}",
            "responseCode": 200
          },
          "input": {
            "type": "structure",
            "members": {
              "Data": {
                "type": "blob"
              },
              "ConnectionId": {
                "location": "uri",
                "locationName": "connectionId"
              }
            },
            "required": [
              "ConnectionId",
              "Data"
            ],
            "payload": "Data"
          }
        }
      },
      "shapes": {}
    }
    model.paginators = {
      "pagination": {}
    }
    return model;
  },
  enumerable: true,
  configurable: true
});

module.exports = AWS.ApiGatewayManagementApi;

index.js

const AWS = require('aws-sdk');
require('./patch.js');


exports.handler = async(event) => {
    const connectionId = event.requestContext.connectionId;

    const apigwManagementApi = new AWS.ApiGatewayManagementApi({
      apiVersion: '2018-11-29',
      endpoint: event.requestContext.domainName + '/' + event.requestContext.stage
    });

    await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: connectionId }).promise();

    return {};
};

client.js

const WebSocket = require('ws');
const ws = new WebSocket('wss://****');

  ws.on('open', () => {
    console.log('connected ===================>')
    ws.on('message', data => console.warn(`From server: ${data}`));
  });

Ошибкав cloudwatch

{
    "errorMessage": "410",
    "errorType": "UnknownError",
    "stackTrace": [
        "Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)",
        "Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:52:8)",
        "Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)",
        "Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)",
        "Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)",
        "Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)",
        "AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)",
        "/var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10",
        "Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)",
        "Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)"
    ]
}

Я не знаю, почему, но если я пытаюсь выполнить пользовательский маршрут, этот код может работать.Кто-нибудь знает, как это решить?

1 Ответ

0 голосов
/ 09 июля 2019

Единственный способ, с помощью которого я нашел эту работу, - это использовать таблицу DynamoDB для хранения соединений, а затем настроить триггер из таблицы обратно в функцию Lambda.

Хотя есть несколько уловов. Эта лямбда-функция не будет работать, как ваш файл index.js выше. Вам нужно будет использовать NPM install --save aws-sdk в папке с файлом index.js, сжать его и загрузить в функцию lambda, чтобы SDK был локализован.

Вам также потребуется настроить пользователя с надлежащим доступом и поместить учетные данные в вашу функцию Lambda.

Обратите внимание: если вы видите ошибку 410, это означает, что соединения больше нет, поэтому вы идете в правильном направлении в этой точке.

const AWS = require('aws-sdk');
require('./patch.js');
var log = console.log;

AWS.config.update({
    accessKeyId: "YOURDATAHERE",
    secretAccessKey: "YOURDATAHERE"
  });

let send = undefined;

function init() {
  const apigwManagementApi = new AWS.ApiGatewayManagementApi({
    apiVersion: '2018-11-29',
    endpoint: "HARDCODEYOURENDPOINTHERE"
  });
  send = async (connectionId, data) => {

        await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: `${data}` }).promise();

  }
}

exports.handler = async (event, context) => {
    init();
    console.log('Received event:', JSON.stringify(event, null, 2));
    for (const record of event.Records) {
        //console.log(record.eventID);
        console.log(record.eventName);
        console.log('DynamoDB Record: %j', record.dynamodb);
        if(record.eventName == "INSERT"){
            var connectionId = record.dynamodb.NewImage.connectionId.S;
                try{
                    await send(connectionId, connectionId);
                }catch(err){
                    log("Error", err);
                }      
            log("sent");
        }
    }
    return `Successfully processed ${event.Records.length} records.`;
};
...