Skip to content

Commit

Permalink
fix: missing UI connections in console (#6509)
Browse files Browse the repository at this point in the history
Fixes #6458

Some UI connections were missing in the Wing Console because when generating information about different resource nodes, inflight closures created in Winglang were treated as resources while inflight closures created using the TypeScript framework were not. To fix this discrepancy, this PR changes how connections are generated so that all intermediate inflight closures are no longer modeled as nodes. Instead, inflight closures (both those created in Winglang and in TypeScript) are explored until resource-like nodes are reached.

Taking this app as an example:

```js
let b = new cloud.Bucket();

let listData = inflight () => {
    b.list();
};

new cloud.Function(inflight () => {
    listData();
    b.put("hello.txt", "world");
});
```

Previously the SDK generated this connection data:

```js
{
  "source": "root/Default/$Closure1_0",
  "sourceOp": "handle",
  "target": "root/Default/Bucket",
  "targetOp": "list",
  "name": "list"
},
{
  "source": "root/Default/$Closure2_0",
  "sourceOp": "handle",
  "target": "root/Default/Bucket",
  "targetOp": "put",
  "name": "put"
},
{
  "source": "root/Default/$Closure2_0",
  "sourceOp": "handle",
  "target": "root/Default/$Closure1_0",
  "targetOp": "handle",
  "name": "handle"
},
{
  "source": "root/Default/Function",
  "sourceOp": "invoke",
  "target": "root/Default/$Closure2_0",
  "targetOp": "handle",
  "name": "handle"
},
{
  "source": "root/Default/Function",
  "sourceOp": "invokeAsync",
  "target": "root/Default/$Closure2_0",
  "targetOp": "handle",
  "name": "handle"
}
```

Now it generates this connection data (note that all "closure" nodes are gone - we just emit relationships between real resources):

```js
{
  "source": "root/Default/Function",
  "sourceOp": "invoke",
  "target": "root/Default/Bucket",
  "targetOp": "put",
  "name": "put"
},
{
  "source": "root/Default/Function",
  "sourceOp": "invoke",
  "target": "root/Default/Bucket",
  "targetOp": "list",
  "name": "list"
},
{
  "source": "root/Default/Function",
  "sourceOp": "invokeAsync",
  "target": "root/Default/Bucket",
  "targetOp": "put",
  "name": "put"
},
{
  "source": "root/Default/Function",
  "sourceOp": "invokeAsync",
  "target": "root/Default/Bucket",
  "targetOp": "list",
  "name": "list"
}
```

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
Chriscbr authored May 17, 2024
1 parent 76ae4db commit d65e4c0
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 38 deletions.
9 changes: 9 additions & 0 deletions libs/wingsdk/src/cloud/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,15 @@ export interface ApiConnectOptions {}
*/
export interface IApiClient {}

/**
* List of inflight operations available for `Api`.
* @internal
*/
export enum ApiInflightMethods {
/** When the API endpoint receives a request. */
REQUEST = "request",
}

/**
* Allowed HTTP methods for a endpoint.
*/
Expand Down
5 changes: 4 additions & 1 deletion libs/wingsdk/src/cloud/bucket.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from "fs";
import { isAbsolute, resolve } from "path";
import { Construct } from "constructs";
import { ITopicOnMessageHandler, Topic } from "./topic";
import { ITopicOnMessageHandler, Topic, TopicInflightMethods } from "./topic";
import { fqnForType } from "../constants";
import { App } from "../core";
import { AbstractMemberError } from "../core/errors";
Expand Down Expand Up @@ -143,6 +143,7 @@ export class Bucket extends Resource {
source: this,
sourceOp: op,
target: topic,
targetOp: TopicInflightMethods.PUBLISH,
name: BucketEventType.CREATE,
});
}
Expand All @@ -159,6 +160,7 @@ export class Bucket extends Resource {
source: this,
sourceOp: op,
target: topic,
targetOp: TopicInflightMethods.PUBLISH,
name: BucketEventType.UPDATE,
});
}
Expand All @@ -175,6 +177,7 @@ export class Bucket extends Resource {
source: this,
sourceOp: op,
target: topic,
targetOp: TopicInflightMethods.PUBLISH,
name: BucketEventType.DELETE,
});
}
Expand Down
9 changes: 9 additions & 0 deletions libs/wingsdk/src/cloud/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ export interface IScheduleOnTickHandler extends IInflight {
*/
export interface IScheduleClient {}

/**
* List of inflight operations available for `Schedule`.
* @internal
*/
export enum ScheduleInflightMethods {
/** When the schedule runs its scheduled actions. */
TICK = "tick",
}

/**
* Inflight client for `IScheduleOnTickHandler`.
*/
Expand Down
35 changes: 23 additions & 12 deletions libs/wingsdk/src/std/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ export interface IHostedLiftable extends ILiftable {
onLift(host: IInflightHost, ops: string[]): void;
}

function hasLiftMap(x: any): x is { _liftMap: LiftMap } {
return x != null && typeof x._liftMap === "object";
}

/**
* Abstract interface for `Resource`.
* @skipDocs
Expand Down Expand Up @@ -193,26 +197,33 @@ export abstract class Resource extends Construct implements IResource {
* @internal
*/
public _preSynthesize(): void {
if ((this as IHostedLiftable)._liftMap === undefined) {
return;
if (hasLiftMap(this) && !(this instanceof AutoIdResource)) {
addConnectionsFromLiftMap(this, this._liftMap);
}
}
}

const data = (this as IHostedLiftable)._liftMap!;
for (const [op, liftEntries] of Object.entries(data)) {
for (const [dep, depOps] of liftEntries) {
if (!Construct.isConstruct(dep)) {
continue;
}

function addConnectionsFromLiftMap(
construct: IConstruct,
liftData: LiftMap,
baseOp?: string
) {
for (const [op, liftEntries] of Object.entries(liftData)) {
for (const [dep, depOps] of liftEntries) {
if (Construct.isConstruct(dep) && !(dep instanceof AutoIdResource)) {
// case 1: dep is an ordinary resource
for (const depOp of depOps) {
Node.of(this).addConnection({
source: this,
sourceOp: op,
Node.of(construct).addConnection({
source: construct,
sourceOp: baseOp ?? op,
target: dep,
targetOp: depOp,
name: depOp,
});
}
} else if (hasLiftMap(dep)) {
// case 2: dep is an inflight
addConnectionsFromLiftMap(construct, dep._liftMap, baseOp ?? op);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion libs/wingsdk/src/target-sim/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ export class Api extends cloud.Api implements ISimulatorResource {
const fn = this.createOrGetFunction(inflight, props, path, method);
Node.of(this).addConnection({
source: this,
sourceOp: cloud.ApiInflightMethods.REQUEST,
target: fn,
name: `${method.toLowerCase()}()`,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: `${method.toLowerCase()} ${path}`,
});
this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE);
}
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-sim/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export class Queue extends cloud.Queue implements ISimulatorResource {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.QueueInflightMethods.POP,
target: this.dlq.queue,
targetOp: cloud.QueueInflightMethods.PUSH,
name: "dead-letter queue",
});
}
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-sim/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export class Schedule extends cloud.Schedule implements ISimulatorResource {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.ScheduleInflightMethods.TICK,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: "onTick()",
});
this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE);
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-sim/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ export class Topic extends cloud.Topic implements ISimulatorResource {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.TopicInflightMethods.PUBLISH,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE_ASYNC,
name: "subscribeQueue()",
});

Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-aws/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ export class Api extends cloud.Api implements IAwsApi {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.ApiInflightMethods.REQUEST,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: `${lowerMethod}()`,
});
}
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-aws/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export class Queue extends cloud.Queue implements IAwsQueue {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.QueueInflightMethods.PUSH,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: "setConsumer()",
});

Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-aws/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export class Schedule extends cloud.Schedule {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.ScheduleInflightMethods.TICK,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: "onTick()",
});

Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-aws/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ export class Topic extends cloud.Topic implements IAwsTopic {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.TopicInflightMethods.PUBLISH,
target: fn,
targetOp: cloud.FunctionInflightMethods.INVOKE_ASYNC,
name: "onMessage()",
});

Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-tf-gcp/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ export class Schedule extends cloud.Schedule {

Node.of(this).addConnection({
source: this,
sourceOp: cloud.ScheduleInflightMethods.TICK,
target: cronFunction,
targetOp: cloud.FunctionInflightMethods.INVOKE,
name: "onTick()",
});

Expand Down
Loading

0 comments on commit d65e4c0

Please sign in to comment.