Skip to content

Commit

Permalink
added support for websockets
Browse files Browse the repository at this point in the history
  • Loading branch information
kenpachiii committed Sep 5, 2019
1 parent 1197f4d commit 0251990
Show file tree
Hide file tree
Showing 22 changed files with 689 additions and 594 deletions.
29 changes: 6 additions & 23 deletions DomainInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,8 @@ import { Domain, ServerlessInstance, ServerlessOptions } from "./types";
*/
class DomainInfo {

// AWS SDK resources
public apigateway: any;
public apigatewayv2: any;
public route53: any;
public acm: any;
public acmRegion: string;
public cloudformation: any;

public serverless: any;

public domainName: string;
public basePath?: string | undefined = "(none)";
public basePath?: string | undefined = "";
public stage?: string | undefined;
public certificateName?: string | undefined;
public certificateArn?: string | undefined;
Expand All @@ -41,21 +31,14 @@ class DomainInfo {
tls_1_2: "TLS_1_2",
};

private defaultHostedZoneId = "Z2FDTNDATAQYW2";
private fallbackHostedZoneId = "Z2FDTNDATAQYW2";

constructor(domain: Domain, serverless: ServerlessInstance, options: ServerlessOptions) {
this.domainName = domain.domainName;

let credentials;
credentials = serverless.providers.aws.getCredentials();

this.apigateway = new serverless.providers.aws.sdk.APIGateway(credentials);
this.apigatewayv2 = new serverless.providers.aws.sdk.ApiGatewayV2(credentials);
this.route53 = new serverless.providers.aws.sdk.Route53(credentials);
this.cloudformation = new serverless.providers.aws.sdk.CloudFormation(credentials);
this.acm = new serverless.providers.aws.sdk.ACM(credentials);

this.serverless = serverless;
if (typeof this.domainName === "undefined") {
throw new Error(`domainName is required. Pass it on your serverless.yaml file.`);
}

if (typeof domain.enabled !== "undefined") {
this.enabled = this.evaluateEnabled(domain.enabled);
Expand Down Expand Up @@ -114,7 +97,7 @@ class DomainInfo {

public SetApiGatewayRespV1(data: any) {
this.aliasTarget = data.distributionDomainName || data.regionalDomainName;
this.aliasHostedZoneId = data.distributionHostedZoneId || data.regionalHostedZoneId;
this.aliasHostedZoneId = data.distributionHostedZoneId || data.regionalHostedZoneId || this.fallbackHostedZoneId;
}

public SetApiGatewayRespV2(data: any) {
Expand Down
95 changes: 59 additions & 36 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,21 @@ class ServerlessCustomDomain {
*/
public async hookWrapper(lifecycleFunc: any) {

this.initializeVariables();
this.initializeDomainManager();

if (this.domains.size === 0) {
const msg = "No domains are enabled. To use Domain Manager pass 'enabled: true' in your serverless.yaml";
this.domainManagerLog(msg);
}

return await lifecycleFunc.call(this);
}

/**
* Lifecycle function to create a domain
* Wraps creating a domain and resource record set
*/
// TODO: refigure so only the needed components are retried
public async createDomains(): Promise<void> {

const iterator = this.domains.entries();
Expand Down Expand Up @@ -116,7 +123,7 @@ class ServerlessCustomDomain {
* Lifecycle function to delete a domain
* Wraps deleting a domain and resource record set
*/

// TODO: refigure so only the needed components are retried
public async deleteDomains(): Promise<void> {

const iterator = this.domains.entries();
Expand All @@ -130,7 +137,7 @@ class ServerlessCustomDomain {
await this.deleteCustomDomain(domainInfo);
await this.changeResourceRecordSet("DELETE", domainInfo);

const msg = `Custom domain ${domainInfo.domainName} was deleted.`;
const msg = `Domain ${domainInfo.domainName} was deleted.`;
results.set(domain.value[0], msg);
domain = iterator.next();
} catch (err) {
Expand Down Expand Up @@ -161,41 +168,51 @@ class ServerlessCustomDomain {
/**
* Lifecycle function to setup API mappings for HTTP and websocket endpoints
*/
// TODO: refigure so only the needed components are retried
public async propogateMappings(): Promise<void> {
const iterator = this.domains.entries();
const successful = new Map();

let domain = iterator.next();
while (!domain.done) {
const domainInfo = domain.value[1];
try {

if (domainInfo.enabled) {

const apiId = await this.getApiId(domainInfo);
this.serverless.cli.log(apiId);
const mapping = await this.getMapping(apiId, domainInfo);

if (!mapping.id) {
if (!mapping) {
await this.createApiMapping(apiId, domainInfo);
domain = iterator.next();
this.addOutputs(domainInfo);
successful.set(domainInfo, "successful");
continue;
}

if (mapping.key !== domainInfo.basePath) {
await this.updateApiMapping(mapping.id, domainInfo, apiId);
if (mapping.apiMappingKey !== domainInfo.basePath) {
await this.updateApiMapping(mapping.apiMappingId, domainInfo, apiId);
domain = iterator.next();
this.addOutputs(domainInfo);
successful.set(domainInfo, "successful");
continue;
} else {
this.logIfDebug(`Path for ${domainInfo.domain} is already current. Skipping...`);
this.logIfDebug(`Path for ${domainInfo.domainName} is already current. Skipping...`);
domain = iterator.next();
}

}
} catch (err) {
this.logIfDebug(err.message);
domain = iterator.next();
}
}

await this.domainSummary();
if (successful.size > 0) {
await this.domainSummary();
}
}

/**
Expand All @@ -209,20 +226,22 @@ class ServerlessCustomDomain {
let domain = iterator.next();
while (!domain.done) {
const domainInfo = domain.value[1];
try {
await this.getAliasInfo(domainInfo);
results.set(domain.value[0], {
aliasHostedZoneId: domainInfo.aliasHostedZoneId,
aliasTarget: domainInfo.aliasTarget,
domainName: domainInfo.domainName,
websocket: domainInfo.websocket,
});
domain = iterator.next();
} catch (err) {
const msg = `Unable to print Serverless Domain Manager Summary for ${domainInfo.domainName}`;
this.domainManagerLog(err);
results.set(domain.value[0], msg);
domain = iterator.next();
if (domainInfo.createRoute53Record !== false) {
try {
await this.getAliasInfo(domainInfo);
results.set(domain.value[0], {
aliasHostedZoneId: domainInfo.aliasHostedZoneId,
aliasTarget: domainInfo.aliasTarget,
domainName: domainInfo.domainName,
websocket: domainInfo.websocket,
});
domain = iterator.next();
} catch (err) {
const msg = `Unable to print Serverless Domain Manager Summary for ${domainInfo.domainName}`;
this.domainManagerLog(err);
results.set(domain.value[0], msg);
domain = iterator.next();
}
}
}

Expand All @@ -232,10 +251,12 @@ class ServerlessCustomDomain {
}

/**
* Goes through custom domain property and initializes local variables and cloudformation template
* Initializes DomainInfo class with domain specific variables, and
* SDK APIs if and only if there are enabled domains. Otherwise will
* return undefined.
*/

public initializeVariables(): void {
public initializeDomainManager(): void {

if (typeof this.serverless.service.custom === "undefined") {
throw new Error("serverless-domain-manager: Plugin configuration is missing.");
Expand Down Expand Up @@ -338,6 +359,7 @@ class ServerlessCustomDomain {
try {
const domainInfo = await this.apigatewayv2.getDomainName({ DomainName: domain.domainName }).promise();
domain.SetApiGatewayRespV2(domainInfo);
this.domains.set(domain.domainName, domain);
} catch (err) {
if (err.code === "NotFoundException") {
throw err;
Expand Down Expand Up @@ -372,6 +394,7 @@ class ServerlessCustomDomain {

createdDomain = await this.apigateway.createDomainName(params).promise();
domain.SetApiGatewayRespV1(createdDomain);
this.domains.set(domain.domainName, domain);
} else {
const params = {
DomainName: domain.domainName,
Expand All @@ -385,6 +408,7 @@ class ServerlessCustomDomain {

createdDomain = await this.apigatewayv2.createDomainName(params).promise();
domain.SetApiGatewayRespV2(createdDomain);
this.domains.set(domain.domainName, domain);
}

} catch (err) {
Expand Down Expand Up @@ -527,8 +551,8 @@ class ServerlessCustomDomain {
};

let mappingInfo;
let currentMappingId;
let currentMappingKey;
let apiMappingId;
let apiMappingKey;

try {
mappingInfo = await this.apigatewayv2.getApiMappings(params).promise();
Expand All @@ -542,17 +566,14 @@ class ServerlessCustomDomain {
if (mappingInfo.Items !== undefined && mappingInfo.Items instanceof Array) {
for (const m of mappingInfo.Items) {
if (m.ApiId === ApiId) {
currentMappingId = m.ApiMappingId;
currentMappingKey = m.ApiMappingKey;
apiMappingId = m.ApiMappingId;
apiMappingKey = m.ApiMappingKey;
break;
}
}
}

return {
id: currentMappingId,
key: currentMappingKey,
};
return apiMappingId ? {apiMappingId, apiMappingKey} : undefined;
}

/**
Expand All @@ -570,7 +591,7 @@ class ServerlessCustomDomain {
await this.apigatewayv2.createApiMapping(params).promise();
this.domainManagerLog(`Created API mapping for ${domain.domainName}.`);
} catch (err) {
throw new Error(`Unable to create an API mapping for ${domain.domainName}.\n`);
throw new Error(`${err}`);
}
}

Expand Down Expand Up @@ -627,6 +648,8 @@ class ServerlessCustomDomain {
} else {
params.LogicalResourceId = "WebsocketsApi";
}
const str = JSON.stringify(params, null, 4);
this.serverless.cli.log(str);

let response;
try {
Expand Down Expand Up @@ -685,7 +708,7 @@ class ServerlessCustomDomain {
*/
public logIfDebug(message: any): void {
if (process.env.SLS_DEBUG) {
this.serverless.cli.log(message, "Domain Manager [DEBUG]");
this.serverless.cli.log(message, "Domain Manager");
}
}

Expand Down Expand Up @@ -739,8 +762,8 @@ class ServerlessCustomDomain {
if (typeof v === "object") {
const apiType = !v.websocket ? "REST" : "Websocket";
this.serverless.cli.consoleLog(chalk.yellow(`${v.domainName} (${apiType}):`));
this.serverless.cli.consoleLog(` Alias Target: ${v.aliasTarget}`);
this.serverless.cli.consoleLog(` Alias Hosted Zone Id: ${v.aliasHostedZoneId}`);
this.serverless.cli.consoleLog(` Target Domain: ${v.aliasTarget}`);
this.serverless.cli.consoleLog(` Hosted Zone Id: ${v.aliasHostedZoneId}`);
} else {
this.serverless.cli.consoleLog(print);
}
Expand Down
Loading

0 comments on commit 0251990

Please sign in to comment.