From f6eecad25e1eb54d7fcb6d28555b7df6bb43ebfe Mon Sep 17 00:00:00 2001 From: Ben Thomasson Date: Tue, 12 Dec 2017 13:38:56 -0500 Subject: [PATCH] Adds explicit channels between FSMs to add in tracing message flows. * Adds channels between FSMs * Adds FSMTrace model * Adds FSMTrace storage and download Channels between FSMs make the processing pipeline delegation explicit and allow for better instrumentation to trace the state of the entire pipeline including FSM state transitions and message flow through the pipeline. This feature is not turned on by default and is only necessary for debugging or certain kinds of testing. --- awx/network_ui/admin.py | 11 +- awx/network_ui/consumers.py | 18 +- awx/network_ui/designs/models.yml | 45 +++- awx/network_ui/migrations/0022_fsmtrace.py | 27 +++ .../migrations/0023_auto_20171213_1623.py | 73 ++++++ .../migrations/0024_auto_20171213_1949.py | 76 ++++++ awx/network_ui/models.py | 12 + .../static/network_ui/CONTRIBUTING.md | 10 +- awx/network_ui/static/network_ui/Makefile | 2 +- .../static/network_ui/designs/button.yml | 2 +- .../static/network_ui/designs/buttons.yml | 2 +- .../network_ui/designs/device_detail.yml | 2 +- .../static/network_ui/designs/group.yml | 38 +-- .../static/network_ui/designs/hotkeys.yml | 2 +- .../static/network_ui/designs/link.yml | 2 +- .../static/network_ui/designs/messages.yml | 2 + .../static/network_ui/designs/mode.yml | 2 +- .../static/network_ui/designs/move.yml | 2 +- .../static/network_ui/designs/null.yml | 2 +- .../static/network_ui/designs/rack.yml | 2 +- .../static/network_ui/designs/site.yml | 2 +- .../static/network_ui/designs/stream.yml | 2 +- .../static/network_ui/designs/time.yml | 2 +- .../static/network_ui/designs/toolbox.yml | 4 +- .../static/network_ui/designs/view.yml | 2 +- .../static/network_ui/src/buttons.js | 4 +- awx/network_ui/static/network_ui/src/fsm.js | 65 ++++- awx/network_ui/static/network_ui/src/group.js | 14 +- .../static/network_ui/src/hotkeys.fsm.js | 20 +- awx/network_ui/static/network_ui/src/link.js | 2 +- .../static/network_ui/src/messages.js | 22 ++ .../static/network_ui/src/mode.fsm.js | 12 +- .../static/network_ui/src/models.js | 20 +- awx/network_ui/static/network_ui/src/move.js | 6 +- .../network_ui/src/network.ui.controller.js | 223 +++++++++++++----- .../src/network.widgets.controller.js | 147 +++++++++--- .../static/network_ui/src/rack.fsm.js | 4 +- .../static/network_ui/src/site.fsm.js | 4 +- awx/network_ui/static/network_ui/src/time.js | 8 +- .../static/network_ui/src/toolbox.fsm.js | 14 +- awx/network_ui/urls.py | 1 + awx/network_ui/views.py | 23 +- 42 files changed, 718 insertions(+), 215 deletions(-) create mode 100644 awx/network_ui/migrations/0022_fsmtrace.py create mode 100644 awx/network_ui/migrations/0023_auto_20171213_1623.py create mode 100644 awx/network_ui/migrations/0024_auto_20171213_1949.py diff --git a/awx/network_ui/admin.py b/awx/network_ui/admin.py index 0f5abc13b2..b79cbe2ecb 100644 --- a/awx/network_ui/admin.py +++ b/awx/network_ui/admin.py @@ -1,4 +1,3 @@ -# Copyright (c) 2017 Red Hat, Inc from django.contrib import admin from awx.network_ui.models import Device @@ -33,6 +32,8 @@ from awx.network_ui.models import Toolbox from awx.network_ui.models import ToolboxItem +from awx.network_ui.models import FSMTrace + class DeviceAdmin(admin.ModelAdmin): fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq',) @@ -160,3 +161,11 @@ class ToolboxItemAdmin(admin.ModelAdmin): admin.site.register(ToolboxItem, ToolboxItemAdmin) + + +class FSMTraceAdmin(admin.ModelAdmin): + fields = ('fsm_name', 'from_state', 'to_state', 'message_type', 'client', 'trace_session_id', 'order',) + raw_id_fields = ('client',) + + +admin.site.register(FSMTrace, FSMTraceAdmin) diff --git a/awx/network_ui/consumers.py b/awx/network_ui/consumers.py index e15689f865..51151be65c 100644 --- a/awx/network_ui/consumers.py +++ b/awx/network_ui/consumers.py @@ -8,6 +8,7 @@ from awx.network_ui.models import GroupDevice as GroupDeviceMap from awx.network_ui.models import DataSheet, DataBinding, DataType from awx.network_ui.models import Process, Stream from awx.network_ui.models import Toolbox, ToolboxItem +from awx.network_ui.models import FSMTrace from awx.network_ui.serializers import yaml_serialize_topology from awx.network_ui.messages import MultipleMessage, InterfaceCreate, LinkCreate, to_dict import urlparse @@ -262,12 +263,16 @@ class _Persistence(object): print "no sender" return if isinstance(data[1], dict) and client_id != data[1].get('sender'): - logger.error("client_id mismatch expected:", client_id, "actual:", data[1].get('sender')) + logger.error("client_id mismatch expected: %s actual %s", client_id, data[1].get('sender')) logger.error(pformat(data)) return message_type = data[0] message_value = data[1] - message_type_id = MessageType.objects.get_or_create(name=message_type)[0].pk + try: + message_type_id = MessageType.objects.get(name=message_type).pk + except ObjectDoesNotExist, e: + logger.warning("Unsupported message %s", message_type) + return TopologyHistory(topology_id=topology_id, client_id=client_id, message_type_id=message_type_id, @@ -510,6 +515,15 @@ class _Persistence(object): if new_entries: GroupDeviceMap.objects.bulk_create(new_entries) + def onFSMTrace(self, message_value, diagram_id, client_id): + FSMTrace(trace_session_id=message_value['trace_id'], + fsm_name=message_value['fsm_name'], + from_state=message_value['from_state'], + to_state=message_value['to_state'], + order=message_value['order'], + client_id=client_id, + message_type=message_value['recv_message_type'] or "none").save() + persistence = _Persistence() diff --git a/awx/network_ui/designs/models.yml b/awx/network_ui/designs/models.yml index aefebe8483..e0d6303b50 100644 --- a/awx/network_ui/designs/models.yml +++ b/awx/network_ui/designs/models.yml @@ -99,8 +99,8 @@ models: pk: true type: AutoField name: Client - x: -455 - y: 109 + x: -510 + y: 141 - fields: - name: topology_history_id pk: true @@ -136,8 +136,8 @@ models: name: name type: CharField name: MessageType - x: -509 - y: 383 + x: -501 + y: 428 - display: name fields: - name: interface_id @@ -305,8 +305,8 @@ models: name: name type: CharField name: Toolbox - x: -222 - y: 627 + x: 179 + y: 644 - fields: - name: toolbox_item_id pk: true @@ -318,8 +318,37 @@ models: - name: data type: TextField name: ToolboxItem - x: 54 - y: 664 + x: 391 + y: 645 +- fields: + - name: fsm_trace_id + pk: true + type: AutoField + - len: 200 + name: fsm_name + type: CharField + - len: 200 + name: from_state + type: CharField + - len: 200 + name: to_state + type: CharField + - len: 200 + name: message_type + type: CharField + - name: client + ref: Client + ref_field: client_id + type: ForeignKey + - default: 0 + name: trace_session_id + type: IntegerField + - default: 0 + name: order + type: IntegerField + name: FSMTrace + x: -872 + y: 507 modules: [] view: panX: 213.72955551921206 diff --git a/awx/network_ui/migrations/0022_fsmtrace.py b/awx/network_ui/migrations/0022_fsmtrace.py new file mode 100644 index 0000000000..2f72ef79f3 --- /dev/null +++ b/awx/network_ui/migrations/0022_fsmtrace.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0021_toolbox_toolboxitem'), + ] + + operations = [ + migrations.CreateModel( + name='FSMTrace', + fields=[ + ('fsm_trace_id', models.AutoField(serialize=False, primary_key=True)), + ('fsm_name', models.CharField(max_length=200)), + ('from_state', models.CharField(max_length=200)), + ('to_state', models.CharField(max_length=200)), + ('message_type', models.CharField(max_length=200)), + ('trace_session_id', models.IntegerField(default=0)), + ('order', models.IntegerField(default=0)), + ('client', models.ForeignKey(to='network_ui.Client')), + ], + ), + ] diff --git a/awx/network_ui/migrations/0023_auto_20171213_1623.py b/awx/network_ui/migrations/0023_auto_20171213_1623.py new file mode 100644 index 0000000000..892e1be9ad --- /dev/null +++ b/awx/network_ui/migrations/0023_auto_20171213_1623.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + +import yaml + +messages = yaml.load(''' +messages: + - {msg_type: DeviceMove, fields: [msg_type, sender, id, x, y, previous_x, previous_y]} + - {msg_type: DeviceCreate, fields: [msg_type, sender, id, x, y, name, type]} + - {msg_type: DeviceDestroy, fields: [msg_type, sender, id, previous_x, previous_y, previous_name, previous_type]} + - {msg_type: DeviceLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: DeviceSelected, fields: [msg_type, sender, id]} + - {msg_type: DeviceUnSelected, fields: [msg_type, sender, id]} + - {msg_type: InterfaceCreate, fields: [msg_type, sender, device_id, id, name]} + - {msg_type: InterfaceLabelEdit, fields: [msg_type, sender, id, device_id, name, previous_name]} + - {msg_type: LinkLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: LinkCreate, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]} + - {msg_type: LinkDestroy, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]} + - {msg_type: LinkSelected, fields: [msg_type, sender, id]} + - {msg_type: LinkUnSelected, fields: [msg_type, sender, id]} + - {msg_type: Undo, fields: [msg_type, sender, original_message]} + - {msg_type: Redo, fields: [msg_type, sender, original_message]} + - {msg_type: Deploy, fields: [msg_type, sender]} + - {msg_type: Destroy, fields: [msg_type, sender]} + - {msg_type: Discover, fields: [msg_type, sender]} + - {msg_type: Layout, fields: [msg_type, sender]} + - {msg_type: MultipleMessage, fields: [msg_type, sender, messages]} + - {msg_type: Coverage, fields: [msg_type, sender, coverage]} + - {msg_type: MouseEvent, fields: [msg_type, sender, x, y, type]} + - {msg_type: MouseWheelEvent, fields: [msg_type, sender, delta, deltaX, deltaY, type, originalEvent]} + - {msg_type: KeyEvent, fields: [msg_type, sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey]} + - {msg_type: TouchEvent, fields: [msg_type, sender, type, touches]} + - {msg_type: StartRecording, fields: [msg_type, sender]} + - {msg_type: StopRecording, fields: [msg_type, sender]} + - {msg_type: ViewPort, fields: [msg_type, sender, scale, panX, panY]} + - {msg_type: CopySite, fields: [msg_type, site]} + - {msg_type: GroupMove, fields: [msg_type, sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2]} + - {msg_type: GroupCreate, fields: [msg_type, sender, id, x1, y1, x2, y2, name, type]} + - {msg_type: GroupDestroy, fields: [msg_type, sender, id, previous_x1, previous_y1, previous_x2, previous_y2, previous_name, previous_type]} + - {msg_type: GroupLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: GroupSelected, fields: [msg_type, sender, id]} + - {msg_type: GroupUnSelected, fields: [msg_type, sender, id]} + - {msg_type: GroupMembership, fields: [msg_type, sender, id, members]} + - {msg_type: TableCellEdit, fields: [msg_type, sender, sheet, col, row, old_value, new_value]} + - {msg_type: ProcessCreate, fields: [msg_type, id, name, type, device_id, x, y]} + - {msg_type: StreamCreate, fields: [msg_type, sender, id, from_id, to_id, label]} + - {msg_type: StreamDestroy, fields: [msg_type, sender, id, from_id, to_id, label]} + - {msg_type: StreamLabelEdit, fields: [msg_type, sender, id, label, previous_label]} + - {msg_type: StreamSelected, fields: [msg_type, sender, id]} + - {msg_type: StreamUnSelected, fields: [msg_type, sender, id]} +''') + + +def populate_message_types(apps, schema_editor): + + MessageType = apps.get_model('network_ui', 'MessageType') + for message in messages['messages']: + MessageType.objects.get_or_create(name=message['msg_type']) + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0022_fsmtrace'), + ] + + operations = [ + migrations.RunPython( + code=populate_message_types, + ), + ] diff --git a/awx/network_ui/migrations/0024_auto_20171213_1949.py b/awx/network_ui/migrations/0024_auto_20171213_1949.py new file mode 100644 index 0000000000..6b1f08eb65 --- /dev/null +++ b/awx/network_ui/migrations/0024_auto_20171213_1949.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + +import yaml + +messages = yaml.load(''' +messages: + - {msg_type: DeviceMove, fields: [msg_type, sender, id, x, y, previous_x, previous_y]} + - {msg_type: DeviceCreate, fields: [msg_type, sender, id, x, y, name, type]} + - {msg_type: DeviceDestroy, fields: [msg_type, sender, id, previous_x, previous_y, previous_name, previous_type]} + - {msg_type: DeviceLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: DeviceSelected, fields: [msg_type, sender, id]} + - {msg_type: DeviceUnSelected, fields: [msg_type, sender, id]} + - {msg_type: InterfaceCreate, fields: [msg_type, sender, device_id, id, name]} + - {msg_type: InterfaceLabelEdit, fields: [msg_type, sender, id, device_id, name, previous_name]} + - {msg_type: LinkLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: LinkCreate, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]} + - {msg_type: LinkDestroy, fields: [msg_type, id, sender, name, from_device_id, to_device_id, from_interface_id, to_interface_id]} + - {msg_type: LinkSelected, fields: [msg_type, sender, id]} + - {msg_type: LinkUnSelected, fields: [msg_type, sender, id]} + - {msg_type: Undo, fields: [msg_type, sender, original_message]} + - {msg_type: Redo, fields: [msg_type, sender, original_message]} + - {msg_type: Deploy, fields: [msg_type, sender]} + - {msg_type: Destroy, fields: [msg_type, sender]} + - {msg_type: Discover, fields: [msg_type, sender]} + - {msg_type: Layout, fields: [msg_type, sender]} + - {msg_type: MultipleMessage, fields: [msg_type, sender, messages]} + - {msg_type: Coverage, fields: [msg_type, sender, coverage]} + - {msg_type: MouseEvent, fields: [msg_type, sender, x, y, type]} + - {msg_type: MouseWheelEvent, fields: [msg_type, sender, delta, deltaX, deltaY, type, originalEvent]} + - {msg_type: KeyEvent, fields: [msg_type, sender, key, keyCode, type, altKey, shiftKey, ctrlKey, metaKey]} + - {msg_type: TouchEvent, fields: [msg_type, sender, type, touches]} + - {msg_type: StartRecording, fields: [msg_type, sender]} + - {msg_type: StopRecording, fields: [msg_type, sender]} + - {msg_type: ViewPort, fields: [msg_type, sender, scale, panX, panY]} + - {msg_type: CopySite, fields: [msg_type, site]} + - {msg_type: GroupMove, fields: [msg_type, sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2]} + - {msg_type: GroupCreate, fields: [msg_type, sender, id, x1, y1, x2, y2, name, type]} + - {msg_type: GroupDestroy, fields: [msg_type, sender, id, previous_x1, previous_y1, previous_x2, previous_y2, previous_name, previous_type]} + - {msg_type: GroupLabelEdit, fields: [msg_type, sender, id, name, previous_name]} + - {msg_type: GroupSelected, fields: [msg_type, sender, id]} + - {msg_type: GroupUnSelected, fields: [msg_type, sender, id]} + - {msg_type: GroupMembership, fields: [msg_type, sender, id, members]} + - {msg_type: TableCellEdit, fields: [msg_type, sender, sheet, col, row, old_value, new_value]} + - {msg_type: ProcessCreate, fields: [msg_type, id, name, type, device_id, x, y]} + - {msg_type: StreamCreate, fields: [msg_type, sender, id, from_id, to_id, label]} + - {msg_type: StreamDestroy, fields: [msg_type, sender, id, from_id, to_id, label]} + - {msg_type: StreamLabelEdit, fields: [msg_type, sender, id, label, previous_label]} + - {msg_type: StreamSelected, fields: [msg_type, sender, id]} + - {msg_type: StreamUnSelected, fields: [msg_type, sender, id]} + - {msg_type: FSMTrace, fields: [msg_type, order, sender, trace_id, fsm_name, from_state, to_state, recv_message_type]} + - {msg_type: ChannelTrace, fields: [msg_type, sender, trace_id, from_fsm, to_fsm, sent_message_type]} + + ''') + + +def populate_message_types(apps, schema_editor): + + MessageType = apps.get_model('network_ui', 'MessageType') + for message in messages['messages']: + MessageType.objects.get_or_create(name=message['msg_type']) + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0023_auto_20171213_1623'), + ] + + operations = [ + migrations.RunPython( + code=populate_message_types, + ), + ] diff --git a/awx/network_ui/models.py b/awx/network_ui/models.py index 9c538fb450..e454c88a3d 100644 --- a/awx/network_ui/models.py +++ b/awx/network_ui/models.py @@ -156,3 +156,15 @@ class ToolboxItem(models.Model): toolbox_item_id = models.AutoField(primary_key=True,) toolbox = models.ForeignKey('Toolbox',) data = models.TextField() + + +class FSMTrace(models.Model): + + fsm_trace_id = models.AutoField(primary_key=True,) + fsm_name = models.CharField(max_length=200,) + from_state = models.CharField(max_length=200,) + to_state = models.CharField(max_length=200,) + message_type = models.CharField(max_length=200,) + client = models.ForeignKey('Client',) + trace_session_id = models.IntegerField(default=0) + order = models.IntegerField(default=0) diff --git a/awx/network_ui/static/network_ui/CONTRIBUTING.md b/awx/network_ui/static/network_ui/CONTRIBUTING.md index d466999583..45b3eb5de8 100644 --- a/awx/network_ui/static/network_ui/CONTRIBUTING.md +++ b/awx/network_ui/static/network_ui/CONTRIBUTING.md @@ -571,11 +571,11 @@ The messages defined are [src/messages.js](src/messages.js): **Message Passing** -Messages are passed along channels between FSMs and over the websocket to and from the -server. Messages from the server over the web socket and user input events from the web -browser are passed to the `first_controller` where they are handled and discarded or -passed along the chain of FSMControllers until they reach the end with `null_controller` -or they are handled and the models are updated. +Messages are passed along channels between FSMs and over the websocket to and +from the server. Messages from the server over the web socket and user input +events from the web browser are passed to the `first_channel` where they are +passed along the chain of FSMControllers until they reach the end with +`NullChannel` or they are handled and the models are updated. * See: [src/network.ui.controller.js](src/network.ui.controller.js#L115) diff --git a/awx/network_ui/static/network_ui/Makefile b/awx/network_ui/static/network_ui/Makefile index 4ef346b42f..df9deb6ef1 100644 --- a/awx/network_ui/static/network_ui/Makefile +++ b/awx/network_ui/static/network_ui/Makefile @@ -29,7 +29,7 @@ istanbul: main simple-server: lint main lessc - python -m SimpleHTTPServer 8081 + python -m SimpleHTTPServer 8082 deploy: main diff --git a/awx/network_ui/static/network_ui/designs/button.yml b/awx/network_ui/static/network_ui/designs/button.yml index 7441dc345e..868def3e9a 100644 --- a/awx/network_ui/static/network_ui/designs/button.yml +++ b/awx/network_ui/static/network_ui/designs/button.yml @@ -1,4 +1,4 @@ -app: button +app: button_fsm panX: 53 panY: -52 scaleXY: 1 diff --git a/awx/network_ui/static/network_ui/designs/buttons.yml b/awx/network_ui/static/network_ui/designs/buttons.yml index a0efa20d36..4a9a323b49 100644 --- a/awx/network_ui/static/network_ui/designs/buttons.yml +++ b/awx/network_ui/static/network_ui/designs/buttons.yml @@ -1,4 +1,4 @@ -app: buttons +app: buttons_fsm panX: 133 panY: 41 scaleXY: 1 diff --git a/awx/network_ui/static/network_ui/designs/device_detail.yml b/awx/network_ui/static/network_ui/designs/device_detail.yml index 810655123e..b2cc6ee5da 100644 --- a/awx/network_ui/static/network_ui/designs/device_detail.yml +++ b/awx/network_ui/static/network_ui/designs/device_detail.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 131 -name: fsm +name: device_detail_fsm states: - id: 2 label: Ready diff --git a/awx/network_ui/static/network_ui/designs/group.yml b/awx/network_ui/static/network_ui/designs/group.yml index 3c36f739c4..dbb4fe7ae6 100644 --- a/awx/network_ui/static/network_ui/designs/group.yml +++ b/awx/network_ui/static/network_ui/designs/group.yml @@ -1,57 +1,57 @@ -finite_state_machine_id: 6 -name: fsm +diagram_id: 38 +name: group_fsm states: -- id: 11 +- id: 1 label: Disable x: 497 y: 84 -- id: 1 +- id: 2 label: Resize x: 571 y: 911 -- id: 2 +- id: 3 label: Start x: 744 y: 69 -- id: 3 - label: CornerSelected - x: 359 - y: 682 -- id: 4 +- id: 5 label: Selected1 x: 839 y: 640 -- id: 5 +- id: 6 label: Selected3 x: 1528 y: 360 -- id: 6 +- id: 7 label: Move x: 1297 y: 786 -- id: 9 +- id: 8 label: Selected2 x: 1179 y: 435 - id: 10 - label: Placing - x: 410 - y: 295 -- id: 7 label: Ready x: 733 y: 304 -- id: 8 +- id: 11 label: EditLabel x: 1130 y: 112 +- id: 4 + label: CornerSelected + x: 526 + y: 554 +- id: 9 + label: Placing + x: 299 + y: 300 transitions: - from_state: CornerSelected label: onMouseMove to_state: Resize - from_state: Placing label: onMouseDown - to_state: CornerSelected + to_state: Resize - from_state: Ready label: onMouseDown to_state: CornerSelected diff --git a/awx/network_ui/static/network_ui/designs/hotkeys.yml b/awx/network_ui/static/network_ui/designs/hotkeys.yml index 95fd1d3982..f499511440 100644 --- a/awx/network_ui/static/network_ui/designs/hotkeys.yml +++ b/awx/network_ui/static/network_ui/designs/hotkeys.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 113 -name: hotkeys +name: hotkeys_fsm states: - id: 2 label: Enabled diff --git a/awx/network_ui/static/network_ui/designs/link.yml b/awx/network_ui/static/network_ui/designs/link.yml index f5227f500f..a9fb63ae8a 100644 --- a/awx/network_ui/static/network_ui/designs/link.yml +++ b/awx/network_ui/static/network_ui/designs/link.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 10 -name: src/link +name: link_fsm states: - id: 5 label: Selecting diff --git a/awx/network_ui/static/network_ui/designs/messages.yml b/awx/network_ui/static/network_ui/designs/messages.yml index ad58b27dd5..92813cb71e 100644 --- a/awx/network_ui/static/network_ui/designs/messages.yml +++ b/awx/network_ui/static/network_ui/designs/messages.yml @@ -42,4 +42,6 @@ messages: - {msg_type: StreamLabelEdit, fields: [msg_type, sender, id, label, previous_label]} - {msg_type: StreamSelected, fields: [msg_type, sender, id]} - {msg_type: StreamUnSelected, fields: [msg_type, sender, id]} + - {msg_type: FSMTrace, fields: [msg_type, order, sender, trace_id, fsm_name, from_state, to_state, recv_message_type]} + - {msg_type: ChannelTrace, fields: [msg_type, sender, trace_id, from_fsm, to_fsm, sent_message_type]} diff --git a/awx/network_ui/static/network_ui/designs/mode.yml b/awx/network_ui/static/network_ui/designs/mode.yml index 8a2a17c1d6..49c5f5952f 100644 --- a/awx/network_ui/static/network_ui/designs/mode.yml +++ b/awx/network_ui/static/network_ui/designs/mode.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 130 -name: mode +name: mode_fsm states: - id: 1 label: Start diff --git a/awx/network_ui/static/network_ui/designs/move.yml b/awx/network_ui/static/network_ui/designs/move.yml index bc6d55ebfb..03d83d72bf 100644 --- a/awx/network_ui/static/network_ui/designs/move.yml +++ b/awx/network_ui/static/network_ui/designs/move.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 13 -name: move +name: move_fsm states: - id: 9 label: Disable diff --git a/awx/network_ui/static/network_ui/designs/null.yml b/awx/network_ui/static/network_ui/designs/null.yml index d8e3e8dd06..6cc188b4a5 100644 --- a/awx/network_ui/static/network_ui/designs/null.yml +++ b/awx/network_ui/static/network_ui/designs/null.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 114 -name: fsm +name: null_fsm states: - id: 1 label: Start diff --git a/awx/network_ui/static/network_ui/designs/rack.yml b/awx/network_ui/static/network_ui/designs/rack.yml index 9ea4bbd27c..d9bffb9cf9 100644 --- a/awx/network_ui/static/network_ui/designs/rack.yml +++ b/awx/network_ui/static/network_ui/designs/rack.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 131 -name: fsm +name: rack_fsm states: - id: 5 label: Selected2 diff --git a/awx/network_ui/static/network_ui/designs/site.yml b/awx/network_ui/static/network_ui/designs/site.yml index 9ea4bbd27c..cb813aab5e 100644 --- a/awx/network_ui/static/network_ui/designs/site.yml +++ b/awx/network_ui/static/network_ui/designs/site.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 131 -name: fsm +name: site_fsm states: - id: 5 label: Selected2 diff --git a/awx/network_ui/static/network_ui/designs/stream.yml b/awx/network_ui/static/network_ui/designs/stream.yml index bb832259b1..c0a1bc1aa7 100644 --- a/awx/network_ui/static/network_ui/designs/stream.yml +++ b/awx/network_ui/static/network_ui/designs/stream.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 82 -name: src/transition +name: stream_fsm states: - id: 4 label: Connecting diff --git a/awx/network_ui/static/network_ui/designs/time.yml b/awx/network_ui/static/network_ui/designs/time.yml index 5ef3634919..8d731b155d 100644 --- a/awx/network_ui/static/network_ui/designs/time.yml +++ b/awx/network_ui/static/network_ui/designs/time.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 11 -name: src/time +name: time_fsm states: - id: 1 label: Present diff --git a/awx/network_ui/static/network_ui/designs/toolbox.yml b/awx/network_ui/static/network_ui/designs/toolbox.yml index e62e5f502d..99fd550b54 100644 --- a/awx/network_ui/static/network_ui/designs/toolbox.yml +++ b/awx/network_ui/static/network_ui/designs/toolbox.yml @@ -1,5 +1,5 @@ -finite_state_machine_id: 24 -name: toolbox +finite_state_machine_id: 14 +name: toolbox_fsm states: - id: 9 label: Disabled diff --git a/awx/network_ui/static/network_ui/designs/view.yml b/awx/network_ui/static/network_ui/designs/view.yml index ee889f5a3e..e06df0cb22 100644 --- a/awx/network_ui/static/network_ui/designs/view.yml +++ b/awx/network_ui/static/network_ui/designs/view.yml @@ -1,5 +1,5 @@ finite_state_machine_id: 15 -name: view +name: view_fsm states: - id: 1 label: Start diff --git a/awx/network_ui/static/network_ui/src/buttons.js b/awx/network_ui/static/network_ui/src/buttons.js index fc0f4e5a50..635b207e78 100644 --- a/awx/network_ui/static/network_ui/src/buttons.js +++ b/awx/network_ui/static/network_ui/src/buttons.js @@ -46,7 +46,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { button = null; } if (button === null) { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; @@ -70,7 +70,7 @@ _Ready.prototype.onMouseMove = function (controller, msg_type, $event) { } } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; diff --git a/awx/network_ui/static/network_ui/src/fsm.js b/awx/network_ui/static/network_ui/src/fsm.js index e7692e1a80..4c04dfa971 100644 --- a/awx/network_ui/static/network_ui/src/fsm.js +++ b/awx/network_ui/static/network_ui/src/fsm.js @@ -1,38 +1,89 @@ /* Copyright (c) 2017 Red Hat, Inc. */ -function FSMController (scope, initial_state, next_controller, name) { +var messages = require('./messages.js'); + +function Channel(from_controller, to_controller, tracer) { + this.tracer = tracer; + this.from_controller = from_controller; + this.to_controller = to_controller; + this.trace = false; +} +exports.Channel = Channel; + +Channel.prototype.send = function(msg_type, message) { + if (this.trace && this.from_controller !== null) { + this.tracer.send_trace_message(new messages.ChannelTrace(this.from_controller.name, + this.to_controller.name, + msg_type)); + } + this.to_controller.handle_message(msg_type, message); +}; + +function NullChannel(from_controller, tracer) { + this.tracer = tracer; + this.from_controller = from_controller; + this.trace = false; +} + +NullChannel.prototype.send = function(msg_type) { + if (this.trace) { + this.tracer.send_trace_message(new messages.ChannelTrace(this.from_controller.name, + 'null', + msg_type)); + } +}; + +function FSMController (scope, name, initial_state, tracer) { this.scope = scope; - this.state = initial_state; - this.next_controller = next_controller; this.name = name; - this.debug = false; + this.state = initial_state; + this.delegate_channel = new NullChannel(this, tracer); + this.tracer = tracer; + this.trace = true; + this.handling_message_type = 'start'; this.state.start(this); + this.handling_message_type = null; } exports.FSMController = FSMController; FSMController.prototype.changeState = function (state) { + var old_handling_message_type; if(this.state !== null) { + old_handling_message_type = this.handling_message_type; + this.handling_message_type = 'end'; this.state.end(this); + this.handling_message_type = old_handling_message_type; + } + if (this.trace) { + this.tracer.send_trace_message(new messages.FSMTrace(this.tracer.trace_order_seq(), + this.name, + this.state.name, + state.name, + this.handling_message_type)); } this.state = state; if(state !== null) { + old_handling_message_type = this.handling_message_type; + this.handling_message_type = 'start'; state.start(this); + this.handling_message_type = old_handling_message_type; } }; FSMController.prototype.handle_message = function(msg_type, message) { + var old_handling_message_type = this.handling_message_type; + this.handling_message_type = msg_type; var handler_name = 'on' + msg_type; if (typeof(this.state[handler_name]) !== "undefined") { this.state[handler_name](this, msg_type, message); } else { this.default_handler(msg_type, message); } + this.handling_message_type = old_handling_message_type; }; FSMController.prototype.default_handler = function(msg_type, message) { - if (this.next_controller !== null) { - this.next_controller.handle_message(msg_type, message); - } + this.delegate_channel.send(msg_type, message); }; function _State () { diff --git a/awx/network_ui/static/network_ui/src/group.js b/awx/network_ui/static/network_ui/src/group.js index c501a281f9..21e705f3b6 100644 --- a/awx/network_ui/static/network_ui/src/group.js +++ b/awx/network_ui/static/network_ui/src/group.js @@ -91,7 +91,7 @@ exports.Placing = Placing; _State.prototype.onUnselectAll = function (controller, msg_type, $event) { controller.changeState(Ready); - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Resize.prototype.onMouseUp = function (controller, msg_type, $event) { @@ -343,7 +343,7 @@ _Move.prototype.end = function (controller) { _Ready.prototype.onMouseMove = function (controller, msg_type, $event) { if (controller.scope.hide_groups) { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); return; } @@ -353,14 +353,14 @@ _Ready.prototype.onMouseMove = function (controller, msg_type, $event) { controller.scope.groups[i].update_hightlighted(controller.scope.scaledX, controller.scope.scaledY); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { if (controller.scope.hide_groups) { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); return; } @@ -402,7 +402,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { } } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Ready.prototype.onMouseDown.transitions = ['Selected1', 'CornerSelected']; @@ -564,7 +564,7 @@ _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { groups[i].name)); } } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Selected2.prototype.onKeyDown.transitions = ['Ready']; @@ -610,5 +610,5 @@ _Placing.prototype.onMouseDown = function (controller) { controller.changeState(Resize); }; -_Placing.prototype.onMouseDown.transitions = ['CornerSelected']; +_Placing.prototype.onMouseDown.transitions = ['Resize']; diff --git a/awx/network_ui/static/network_ui/src/hotkeys.fsm.js b/awx/network_ui/static/network_ui/src/hotkeys.fsm.js index 5af0851548..51b4c1440b 100644 --- a/awx/network_ui/static/network_ui/src/hotkeys.fsm.js +++ b/awx/network_ui/static/network_ui/src/hotkeys.fsm.js @@ -45,16 +45,16 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { var scope = controller.scope; if ($event.key === 'c' && ($event.ctrlKey || $event.metaKey)) { - scope.first_controller.handle_message("CopySelected", $event); + scope.first_channel.send("CopySelected", $event); } if ($event.key === 'l') { - scope.first_controller.handle_message("NewLink", $event); + scope.first_channel.send("NewLink", $event); return; } if ($event.key === 'm') { - scope.first_controller.handle_message("NewStream", $event); + scope.first_channel.send("NewStream", $event); } if ($event.key === 'd') { @@ -75,27 +75,27 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { } if ($event.key === 'r') { - scope.first_controller.handle_message("NewDevice", new messages.NewDevice("router")); + scope.first_channel.send("NewDevice", new messages.NewDevice("router")); return; } else if ($event.key === 's') { - scope.first_controller.handle_message("NewDevice", new messages.NewDevice("switch")); + scope.first_channel.send("NewDevice", new messages.NewDevice("switch")); return; } else if ($event.key === 'a') { - scope.first_controller.handle_message("NewGroup", new messages.NewGroup("rack")); + scope.first_channel.send("NewGroup", new messages.NewGroup("rack")); return; } else if ($event.key === 'h') { - scope.first_controller.handle_message("NewDevice", new messages.NewDevice("host")); + scope.first_channel.send("NewDevice", new messages.NewDevice("host")); return; } else if ($event.key === 'g') { - scope.first_controller.handle_message("NewGroup", new messages.NewGroup("group")); + scope.first_channel.send("NewGroup", new messages.NewGroup("group")); return; } else if ($event.key === 'e') { - scope.first_controller.handle_message("NewGroup", new messages.NewGroup("site")); + scope.first_channel.send("NewGroup", new messages.NewGroup("site")); return; } else if ($event.key === '0') { @@ -106,7 +106,7 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { scope.updatePanAndScale(); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Start.prototype.start = function (controller) { diff --git a/awx/network_ui/static/network_ui/src/link.js b/awx/network_ui/static/network_ui/src/link.js index 5ec1170080..05f17573f5 100644 --- a/awx/network_ui/static/network_ui/src/link.js +++ b/awx/network_ui/static/network_ui/src/link.js @@ -51,7 +51,7 @@ _Ready.prototype.onNewLink = function (controller, msg_type, message) { controller.scope.clear_selections(); controller.changeState(Selecting); - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); }; _Ready.prototype.onNewLink.transitions = ['Selecting']; diff --git a/awx/network_ui/static/network_ui/src/messages.js b/awx/network_ui/static/network_ui/src/messages.js index 3499b3cad5..ef80dd1511 100644 --- a/awx/network_ui/static/network_ui/src/messages.js +++ b/awx/network_ui/static/network_ui/src/messages.js @@ -422,3 +422,25 @@ function StreamUnSelected(sender, id) { this.id = id; } exports.StreamUnSelected = StreamUnSelected; + +function FSMTrace(order, fsm_name, from_state, to_state, recv_message_type) { + this.msg_type = 'FSMTrace'; + this.order = order; + this.sender = 0; + this.trace_id = 0; + this.fsm_name = fsm_name; + this.from_state = from_state; + this.to_state = to_state; + this.recv_message_type = recv_message_type; +} +exports.FSMTrace = FSMTrace; + +function ChannelTrace(from_fsm, to_fsm, sent_message_type) { + this.msg_type = 'ChannelTrace'; + this.sender = 0; + this.trace_id = 0; + this.from_fsm = from_fsm; + this.to_fsm = to_fsm; + this.sent_message_type = sent_message_type; +} +exports.ChannelTrace = ChannelTrace; diff --git a/awx/network_ui/static/network_ui/src/mode.fsm.js b/awx/network_ui/static/network_ui/src/mode.fsm.js index 4749892d8e..bf657dd82d 100644 --- a/awx/network_ui/static/network_ui/src/mode.fsm.js +++ b/awx/network_ui/static/network_ui/src/mode.fsm.js @@ -83,7 +83,7 @@ _Interface.prototype.onMouseWheel = function (controller, msg_type, $event) { //controller.changeState(Device); - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Interface.prototype.onMouseWheel.transitions = ['Device']; @@ -110,7 +110,7 @@ _Site.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.changeState(Rack); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Site.prototype.onMouseWheel.transitions = ['MultiSite', 'Rack']; @@ -119,7 +119,7 @@ _Site.prototype.onMouseWheel.transitions = ['MultiSite', 'Rack']; _Process.prototype.onMouseWheel = function (controller, msg_type, $event) { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); //controller.changeState(Device); @@ -145,7 +145,7 @@ _MultiSite.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.changeState(Site); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _MultiSite.prototype.onMouseWheel.transitions = ['Site']; @@ -171,7 +171,7 @@ _Device.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.changeState(Rack); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Device.prototype.onMouseWheel.transitions = ['Process', 'Interface', 'Rack']; @@ -200,6 +200,6 @@ _Rack.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.changeState(Device); } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Rack.prototype.onMouseWheel.transitions = ['Site', 'Device']; diff --git a/awx/network_ui/static/network_ui/src/models.js b/awx/network_ui/static/network_ui/src/models.js index 47efc02fd0..f57b207339 100644 --- a/awx/network_ui/static/network_ui/src/models.js +++ b/awx/network_ui/static/network_ui/src/models.js @@ -289,7 +289,7 @@ Link.prototype.plength = function (x, y) { return util.pDistance(x, y, x1, y1, x2, y2); }; -function ActionIcon(name, x, y, r, callback, enabled) { +function ActionIcon(name, x, y, r, callback, enabled, tracer) { this.name = name; this.x = x; this.y = y; @@ -298,7 +298,7 @@ function ActionIcon(name, x, y, r, callback, enabled) { this.is_pressed = false; this.mouse_over = false; this.enabled = enabled; - this.fsm = new fsm.FSMController(this, enabled ? button.Start : button.Disabled, null, name+'button_fsm'); + this.fsm = new fsm.FSMController(this, "button_fsm", enabled ? button.Start : button.Disabled, tracer); } exports.ActionIcon = ActionIcon; @@ -311,7 +311,7 @@ ActionIcon.prototype.is_selected = function (x, y) { }; -function Button(name, x, y, width, height, callback) { +function Button(name, x, y, width, height, callback, tracer) { this.name = name; this.x = x; this.y = y; @@ -321,7 +321,7 @@ function Button(name, x, y, width, height, callback) { this.is_pressed = false; this.mouse_over = false; this.enabled = true; - this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); + this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); } exports.Button = Button; @@ -336,7 +336,7 @@ Button.prototype.is_selected = function (x, y) { }; -function ToggleButton(name, x, y, width, height, toggle_callback, untoggle_callback, default_toggled) { +function ToggleButton(name, x, y, width, height, toggle_callback, untoggle_callback, default_toggled, tracer) { this.name = name; this.x = x; this.y = y; @@ -349,7 +349,7 @@ function ToggleButton(name, x, y, width, height, toggle_callback, untoggle_callb this.untoggle_callback = untoggle_callback; this.mouse_over = false; this.enabled = true; - this.fsm = new fsm.FSMController(this, button.Start, null, name+'toggle_button_fsm'); + this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); } inherits(ToggleButton, Button); exports.ToggleButton = ToggleButton; @@ -365,7 +365,7 @@ ToggleButton.prototype.toggle = function () { } }; -function ContextMenu(name, x, y, width, height, callback, enabled, buttons) { +function ContextMenu(name, x, y, width, height, callback, enabled, buttons, tracer) { this.name = name; this.x = x; this.y = y; @@ -376,7 +376,7 @@ function ContextMenu(name, x, y, width, height, callback, enabled, buttons) { this.mouse_over = false; this.enabled = enabled; this.buttons = buttons; - this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); + this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); } exports.ContextMenu = ContextMenu; @@ -390,7 +390,7 @@ ContextMenu.prototype.is_selected = function (x, y) { }; -function ContextMenuButton(name, x, y, width, height, callback) { +function ContextMenuButton(name, x, y, width, height, callback, tracer) { this.name = name; this.x = x; this.y = y; @@ -400,7 +400,7 @@ function ContextMenuButton(name, x, y, width, height, callback) { this.is_pressed = false; this.mouse_over = false; this.enabled = true; - this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); + this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); } exports.ContextMenuButton = ContextMenuButton; diff --git a/awx/network_ui/static/network_ui/src/move.js b/awx/network_ui/static/network_ui/src/move.js index 3a9f9a0d12..3f1fbb70cf 100644 --- a/awx/network_ui/static/network_ui/src/move.js +++ b/awx/network_ui/static/network_ui/src/move.js @@ -79,7 +79,7 @@ exports.Placing = Placing; _State.prototype.onUnselectAll = function (controller, msg_type, $event) { controller.changeState(Ready); - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Ready.prototype.onNewDevice = function (controller, msg_type, message) { @@ -209,7 +209,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { } else if (last_selected.last_selected_interface !== null) { controller.changeState(Selected1); } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Ready.prototype.onMouseDown.transitions = ['Selected1']; @@ -345,7 +345,7 @@ _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { } } - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Selected2.prototype.onKeyDown.transitions = ['Ready']; diff --git a/awx/network_ui/static/network_ui/src/network.ui.controller.js b/awx/network_ui/static/network_ui/src/network.ui.controller.js index d5ad0b59f3..06fafe8669 100644 --- a/awx/network_ui/static/network_ui/src/network.ui.controller.js +++ b/awx/network_ui/static/network_ui/src/network.ui.controller.js @@ -1,5 +1,4 @@ /* Copyright (c) 2017 Red Hat, Inc. */ -// var _ = require('lodash'); var angular = require('angular'); var fsm = require('./fsm.js'); var null_fsm = require('./null.fsm.js'); @@ -30,13 +29,14 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.http = $http; $scope.api_token = ''; - $scope.disconnected = true; + $scope.disconnected = false; $scope.topology_id = $location.search().topology_id || 0; // Create a web socket to connect to the backend server // $scope.inventory_id = $location.search().inventory_id || 1; + $scope.initial_messages = []; if (!$scope.disconnected) { $scope.control_socket = new ReconnectingWebSocket("wss://" + window.location.host + "/network_ui/topology?topology_id=" + $scope.topology_id, null, @@ -112,19 +112,43 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, 'y': 0, 'width': 0, 'height': 0}; + $scope.trace_id_seq = util.natural_numbers(0); + $scope.trace_order_seq = util.natural_numbers(0); + $scope.trace_id = $scope.trace_id_seq(); + + $scope.send_trace_message = function (message) { + console.log(message); + message.sender = $scope.client_id; + message.trace_id = $scope.trace_id; + message.message_id = $scope.message_id_seq(); + var data = messages.serialize(message); + if (!$scope.disconnected) { + try { + $scope.control_socket.send(data); + } + catch(err) { + $scope.initial_messages.push(message); + } + } else { + console.log(data); + } + }; + + //Define the FSMs + $scope.null_controller = new fsm.FSMController($scope, "null_fsm", null_fsm.Start, $scope); + $scope.hotkeys_controller = new fsm.FSMController($scope, "hotkeys_fsm", hotkeys.Start, $scope); + $scope.view_controller = new fsm.FSMController($scope, "view_fsm", view.Start, $scope); + $scope.device_detail_controller = new fsm.FSMController($scope, "device_detail_fsm", device_detail_fsm.Start, $scope); + $scope.move_controller = new fsm.FSMController($scope, "move_fsm", move.Start, $scope); + $scope.link_controller = new fsm.FSMController($scope, "link_fsm", link.Start, $scope); + $scope.stream_controller = new fsm.FSMController($scope, "stream_fsm", stream_fsm.Start, $scope); + $scope.group_controller = new fsm.FSMController($scope, "group_fsm", group.Start, $scope); + $scope.rack_controller = new fsm.FSMController($scope, "rack_fsm", rack_fsm.Disable, $scope); + $scope.site_controller = new fsm.FSMController($scope, "site_fsm", site_fsm.Disable, $scope); + $scope.buttons_controller = new fsm.FSMController($scope, "buttons_fsm", buttons.Start, $scope); + $scope.time_controller = new fsm.FSMController($scope, "time_fsm", time.Start, $scope); + $scope.app_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); - $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null, 'null_fsm'); - $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller, 'hotkeys_fsm'); - $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller, 'null_fsm'); - $scope.device_detail_controller = new fsm.FSMController($scope, device_detail_fsm.Start, $scope.view_controller, 'device_detail_fsm'); - $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.device_detail_controller, 'move_fsm'); - $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller, 'link_fsm'); - $scope.stream_controller = new fsm.FSMController($scope, stream_fsm.Start, $scope.link_controller, 'stream_fsm'); - $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.stream_controller, 'group_fsm'); - $scope.rack_controller = new fsm.FSMController($scope, rack_fsm.Disable, $scope.group_controller, 'rack_fsm'); - $scope.site_controller = new fsm.FSMController($scope, site_fsm.Disable, $scope.rack_controller, 'site_fsm'); - $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.site_controller, 'time_fsm'); - $scope.app_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Disabled, $scope.time_controller, 'toolbox_fsm'); //App Toolbox Setup $scope.app_toolbox = new models.ToolBox(0, 'Process', 'app', 0, 40, 200, $scope.graph.height - 40); $scope.app_toolbox.title_coordinates = {x: 70, y: 70}; @@ -133,7 +157,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.app_toolbox_controller.toolbox = $scope.app_toolbox; $scope.app_toolbox_controller.debug = true; $scope.app_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteProcess", new messages.PasteProcess(selected_item)); + $scope.first_channel.send("PasteProcess", new messages.PasteProcess(selected_item)); }; $scope.app_toolbox.items.push(new models.Process(0, 'BGP', 'process', 0, 0)); @@ -145,19 +169,19 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.app_toolbox.items[i].icon = true; } - $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller, 'inventory_toolbox_fsm'); + $scope.inventory_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); + function add_host (host) { + console.log(host); + var device = new models.Device(0, host.data.name, 0, 0, host.data.type); + device.icon = true; + $scope.inventory_toolbox.items.push(device); + } //Inventory Toolbox Setup $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 0, 40, 200, $scope.graph.height - 40); if (!$scope.disconnected) { console.log($location.protocol() + "://" + $location.host() + ':' + $location.port()); console.log($scope.my_location); - var add_host = function(host) { - console.log(host); - var device = new models.Device(0, host.data.name, 0, 0, host.data.type); - device.icon = true; - $scope.inventory_toolbox.items.push(device); - }; $http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/?format=json') .then(function(inventory) { console.log(inventory); @@ -191,11 +215,11 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.inventory_toolbox_controller.remove_on_drop = true; $scope.inventory_toolbox_controller.debug = true; $scope.inventory_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item)); + $scope.first_channel.send("PasteDevice", new messages.PasteDevice(selected_item)); }; //End Inventory Toolbox Setup - $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller, 'rack_toolbox_fsm'); + $scope.rack_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); //Rack Toolbox Setup $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 0, 40, 200, $scope.graph.height - 40); $scope.rack_toolbox.title_coordinates = {x: 80, y: 70}; @@ -205,14 +229,14 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.rack_toolbox_controller.toolbox = $scope.rack_toolbox; $scope.rack_toolbox_controller.debug = true; $scope.rack_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteRack", new messages.PasteRack(selected_item)); + $scope.first_channel.send("PasteRack", new messages.PasteRack(selected_item)); }; for(i = 0; i < $scope.rack_toolbox.items.length; i++) { $scope.rack_toolbox.items[i].icon = true; $scope.rack_toolbox.items[i].selected = false; } //End Rack Toolbox Setup - $scope.site_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.rack_toolbox_controller, 'site_toolbox_fsm'); + $scope.site_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); //Site Toolbox Setup $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 0, 40, 200, $scope.graph.height - 40); $scope.site_toolbox.title_coordinates = {x: 80, y: 70}; @@ -222,16 +246,67 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.site_toolbox_controller.toolbox = $scope.site_toolbox; $scope.site_toolbox_controller.debug = true; $scope.site_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteSite", new messages.PasteSite(selected_item)); + $scope.first_channel.send("PasteSite", new messages.PasteSite(selected_item)); }; for(i = 0; i < $scope.site_toolbox.items.length; i++) { $scope.site_toolbox.items[i].icon = true; $scope.site_toolbox.items[i].selected = false; } //End Site Toolbox Setup - $scope.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.site_toolbox_controller, 'buttons_fsm'); - $scope.mode_controller = new fsm.FSMController($scope, mode_fsm.Start, $scope.buttons_controller, 'mode_fsm'); - $scope.first_controller = $scope.mode_controller; + + $scope.mode_controller = new fsm.FSMController($scope, "mode_fsm", mode_fsm.Start, $scope); + + //Wire up the FSMs + $scope.view_controller.delegate_channel = new fsm.Channel($scope.view_controller, + $scope.hotkeys_controller, + $scope); + $scope.device_detail_controller.delegate_channel = new fsm.Channel($scope.device_detail_controller, + $scope.view_controller, + $scope); + $scope.move_controller.delegate_channel = new fsm.Channel($scope.move_controller, + $scope.device_detail_controller, + $scope); + $scope.link_controller.delegate_channel = new fsm.Channel($scope.link_controller, + $scope.move_controller, + $scope); + $scope.stream_controller.delegate_channel = new fsm.Channel($scope.stream_controller, + $scope.link_controller, + $scope); + $scope.group_controller.delegate_channel = new fsm.Channel($scope.group_controller, + $scope.stream_controller, + $scope); + $scope.rack_controller.delegate_channel = new fsm.Channel($scope.rack_controller, + $scope.group_controller, + $scope); + $scope.site_controller.delegate_channel = new fsm.Channel($scope.site_controller, + $scope.rack_controller, + $scope); + $scope.app_toolbox_controller.delegate_channel = new fsm.Channel($scope.app_toolbox_controller, + $scope.site_controller, + $scope); + $scope.inventory_toolbox_controller.delegate_channel = new fsm.Channel($scope.inventory_toolbox_controller, + $scope.app_toolbox_controller, + $scope); + $scope.rack_toolbox_controller.delegate_channel = new fsm.Channel($scope.rack_toolbox_controller, + $scope.inventory_toolbox_controller, + $scope); + $scope.site_toolbox_controller.delegate_channel = new fsm.Channel($scope.site_toolbox_controller, + $scope.rack_toolbox_controller, + $scope); + $scope.buttons_controller.delegate_channel = new fsm.Channel($scope.buttons_controller, + $scope.site_toolbox_controller, + $scope); + $scope.time_controller.delegate_channel = new fsm.Channel($scope.time_controller, + $scope.buttons_controller, + $scope); + $scope.mode_controller.delegate_channel = new fsm.Channel($scope.mode_controller, + $scope.time_controller, + $scope); + + $scope.first_channel = new fsm.Channel(null, + $scope.mode_controller, + $scope); + var getMouseEventResult = function (mouseEvent) { return "(" + mouseEvent.x + ", " + mouseEvent.y + ")"; }; @@ -406,7 +481,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseDown', $event); + $scope.first_channel.send('MouseDown', $event); $scope.onMouseDownResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -417,7 +492,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.y, $event.type)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseUp', $event); + $scope.first_channel.send('MouseUp', $event); $scope.onMouseUpResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -444,7 +519,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.mouseX = $event.x; $scope.mouseY = $event.y; $scope.updateScaledXY(); - $scope.first_controller.handle_message('MouseMove', $event); + $scope.first_channel.send('MouseMove', $event); $scope.onMouseMoveResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -471,7 +546,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseWheel', [$event, delta, deltaX, deltaY]); + $scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]); event.preventDefault(); }; @@ -489,7 +564,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.last_event = $event; $scope.last_key = $event.key; $scope.last_key_code = $event.keyCode; - $scope.first_controller.handle_message('KeyDown', $event); + $scope.first_channel.send('KeyDown', $event); $scope.$apply(); $event.preventDefault(); }; @@ -518,7 +593,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.mouseY = $event.touches[0].screenY; $scope.updateScaledXY(); } - $scope.first_controller.handle_message('TouchStart', $event); + $scope.first_channel.send('TouchStart', $event); $scope.onTouchStartEvent = $event; $event.preventDefault(); }; @@ -533,7 +608,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, if ($scope.recording) { $scope.send_control_message(new messages.TouchEvent($scope.client_id, "touchend", touches)); } - $scope.first_controller.handle_message('TouchEnd', $event); + $scope.first_channel.send('TouchEnd', $event); $scope.onTouchEndEvent = $event; $event.preventDefault(); }; @@ -558,7 +633,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.updateScaledXY(); } - $scope.first_controller.handle_message('TouchMove', $event); + $scope.first_channel.send('TouchMove', $event); $scope.onTouchMoveEvent = $event; $event.preventDefault(); }; @@ -586,7 +661,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, // $scope.onToggleToolboxButtonLeft = function (button) { console.log(button.name); - $scope.first_controller.handle_message("ToggleToolbox", {}); + $scope.first_channel.send("ToggleToolbox", {}); $scope.action_icons[0].fsm.handle_message("Disable", {}); $scope.action_icons[1].fsm.handle_message("Enable", {}); $scope.overall_toolbox_collapsed = !$scope.overall_toolbox_collapsed; @@ -594,7 +669,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.onToggleToolboxButtonRight = function (button) { console.log(button.name); - $scope.first_controller.handle_message("ToggleToolbox", {}); + $scope.first_channel.send("ToggleToolbox", {}); $scope.action_icons[0].fsm.handle_message("Enable", {}); $scope.action_icons[1].fsm.handle_message("Disable", {}); $scope.overall_toolbox_collapsed = !$scope.overall_toolbox_collapsed; @@ -696,54 +771,61 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, // Context Menu Buttons $scope.context_menu_buttons = [ - new models.ContextMenuButton("Edit", 210, 200, 160, 26, $scope.onDetailsContextButton), - new models.ContextMenuButton("Details", 236, 231, 160, 26, $scope.onDetailsContextButton) + new models.ContextMenuButton("Edit", 210, 200, 160, 26, $scope.onDetailsContextButton, $scope), + new models.ContextMenuButton("Details", 236, 231, 160, 26, $scope.onDetailsContextButton, $scope) ]; // Context Menus $scope.context_menus = [ - new models.ContextMenu('HOST', 210, 200, 160, 64, $scope.contextMenuCallback, true, $scope.context_menu_buttons) + new models.ContextMenu('HOST', 210, 200, 160, 64, $scope.contextMenuCallback, true, $scope.context_menu_buttons, $scope) ]; // Icons $scope.action_icons = [ - new models.ActionIcon("chevron-left", 170, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonLeft, true), - new models.ActionIcon("chevron-right", 15, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonRight, false) + new models.ActionIcon("chevron-left", 170, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonLeft, true, $scope), + new models.ActionIcon("chevron-right", 15, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonRight, false, $scope) ]; + $scope.onDownloadTraceButton = function (button) { + console.log(button.label); + window.open("/network_ui/download_trace?topology_id=" + $scope.topology_id + "&trace_id=" + $scope.trace_id + "&client_id=" + $scope.client_id); + }; // Buttons var button_offset = 200; $scope.buttons = [ - new models.Button("DEPLOY", button_offset + 10, 48, 70, 30, $scope.onDeployButton), - new models.Button("DESTROY", button_offset + 90, 48, 80, 30, $scope.onDestroyButton), - new models.Button("RECORD", button_offset + 180, 48, 80, 30, $scope.onRecordButton), - new models.Button("EXPORT", button_offset + 270, 48, 70, 30, $scope.onExportButton), - new models.Button("DISCOVER", button_offset + 350, 48, 80, 30, $scope.onDiscoverButton), - new models.Button("LAYOUT", button_offset + 440, 48, 70, 30, $scope.onLayoutButton), - new models.Button("CONFIGURE", button_offset + 520, 48, 90, 30, $scope.onConfigureButton), - new models.Button("EXPORT YAML", button_offset + 620, 48, 120, 30, $scope.onExportYamlButton), + new models.Button("DEPLOY", button_offset + 10, 48, 70, 30, $scope.onDeployButton, $scope), + new models.Button("DESTROY", button_offset + 90, 48, 80, 30, $scope.onDestroyButton, $scope), + new models.Button("RECORD", button_offset + 180, 48, 80, 30, $scope.onRecordButton, $scope), + new models.Button("EXPORT", button_offset + 270, 48, 70, 30, $scope.onExportButton, $scope), + new models.Button("DISCOVER", button_offset + 350, 48, 80, 30, $scope.onDiscoverButton, $scope), + new models.Button("LAYOUT", button_offset + 440, 48, 70, 30, $scope.onLayoutButton, $scope), + new models.Button("CONFIGURE", button_offset + 520, 48, 90, 30, $scope.onConfigureButton, $scope), + new models.Button("EXPORT YAML", button_offset + 620, 48, 120, 30, $scope.onExportYamlButton, $scope), + new models.Button("DOWNLOAD TRACE", button_offset + 750, 48, 150, 30, $scope.onDownloadTraceButton, $scope), ]; var LAYERS_X = 160; $scope.layers = [ - new models.ToggleButton("APPLICATION", $scope.graph.width - LAYERS_X, 10, 120, 30, util.noop, util.noop, true), - new models.ToggleButton("PRESENTATION", $scope.graph.width - LAYERS_X, 50, 120, 30, util.noop, util.noop, true), - new models.ToggleButton("SESSION", $scope.graph.width - LAYERS_X, 90, 120, 30, util.noop, util.noop, true), - new models.ToggleButton("TRANSPORT", $scope.graph.width - LAYERS_X, 130, 120, 30, util.noop, util.noop, true), - new models.ToggleButton("NETWORK", $scope.graph.width - LAYERS_X, 170, 120, 30, util.noop, util.noop, true), - new models.ToggleButton("DATA-LINK", $scope.graph.width - LAYERS_X, 210, 120, 30, util.noop, util.noop, true), + new models.ToggleButton("APPLICATION", $scope.graph.width - LAYERS_X, 10, 120, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("PRESENTATION", $scope.graph.width - LAYERS_X, 50, 120, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("SESSION", $scope.graph.width - LAYERS_X, 90, 120, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("TRANSPORT", $scope.graph.width - LAYERS_X, 130, 120, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("NETWORK", $scope.graph.width - LAYERS_X, 170, 120, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("DATA-LINK", $scope.graph.width - LAYERS_X, 210, 120, 30, util.noop, util.noop, true, $scope), new models.ToggleButton("PHYSICAL", $scope.graph.width - LAYERS_X, 250, 120, 30, $scope.onTogglePhysical, $scope.onUnTogglePhysical, - true), + true, + $scope), new models.ToggleButton("GROUP", $scope.graph.width - LAYERS_X, 290, 120, 30, $scope.onToggleGroup, $scope.onUnToggleGroup, - true) + true, + $scope) ]; $scope.layers = []; @@ -1213,6 +1295,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.onClientId = function(data) { $scope.client_id = data; + $scope.send_initial_messages(); }; $scope.onTopology = function(data) { @@ -1559,12 +1642,26 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.control_socket.onmessage = function(message) { - $scope.first_controller.handle_message('Message', message); + $scope.first_channel.send('Message', message); $scope.$apply(); }; $scope.control_socket.onopen = function() { - //Ignore + //ignore + }; + + $scope.send_initial_messages = function() { + var i = 0; + var messages_to_send = $scope.initial_messages; + var message = null; + var data = null; + $scope.initial_messages = []; + for(i = 0; i < messages_to_send.length; i++) { + message = messages_to_send[i]; + message.sender = $scope.client_id; + data = messages.serialize(message); + $scope.control_socket.send(data); + } }; // Call onopen directly if $scope.control_socket is already open diff --git a/awx/network_ui/static/network_ui/src/network.widgets.controller.js b/awx/network_ui/static/network_ui/src/network.widgets.controller.js index 7fa35f2453..10529371e7 100644 --- a/awx/network_ui/static/network_ui/src/network.widgets.controller.js +++ b/awx/network_ui/static/network_ui/src/network.widgets.controller.js @@ -32,7 +32,8 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.topology_id = 0; $scope.control_socket = { - on_message: util.noop + on_message: util.noop, + send: util.noop }; $scope.history = []; $scope.client_id = 1; @@ -98,27 +99,45 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { 'y': 0, 'width': 0, 'height': 0}; + $scope.trace_id_seq = util.natural_numbers(0); + $scope.trace_order_seq = util.natural_numbers(0); + $scope.trace_id = $scope.trace_id_seq(); + + $scope.send_trace_message = function (message) { + console.log(message); + message.sender = $scope.client_id; + message.trace_id = $scope.trace_id; + message.message_id = $scope.message_id_seq(); + var data = messages.serialize(message); + if (!$scope.disconnected) { + $scope.control_socket.send(data); + } else { + console.log(data); + } + }; + + //Define the FSMs + $scope.null_controller = new fsm.FSMController($scope, "null_fsm", null_fsm.Start, $scope); + $scope.hotkeys_controller = new fsm.FSMController($scope, "hotkeys_fsm", hotkeys.Start, $scope); + $scope.view_controller = new fsm.FSMController($scope, "view_fsm", view.Start, $scope); + $scope.device_detail_controller = new fsm.FSMController($scope, "device_detail_fsm", device_detail_fsm.Start, $scope); + $scope.move_controller = new fsm.FSMController($scope, "move_fsm", move.Start, $scope); + $scope.link_controller = new fsm.FSMController($scope, "link_fsm", link.Start, $scope); + $scope.stream_controller = new fsm.FSMController($scope, "stream_fsm", stream_fsm.Start, $scope); + $scope.group_controller = new fsm.FSMController($scope, "group_fsm", group.Start, $scope); + $scope.rack_controller = new fsm.FSMController($scope, "rack_fsm", rack_fsm.Disable, $scope); + $scope.site_controller = new fsm.FSMController($scope, "site_fsm", site_fsm.Disable, $scope); + $scope.buttons_controller = new fsm.FSMController($scope, "buttons_fsm", buttons.Start, $scope); + $scope.time_controller = new fsm.FSMController($scope, "time_fsm", time.Start, $scope); + $scope.app_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); - $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null); - $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller); - $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller); - $scope.device_detail_controller = new fsm.FSMController($scope, device_detail_fsm.Start, $scope.view_controller); - $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.device_detail_controller); - $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller); - $scope.stream_controller = new fsm.FSMController($scope, stream_fsm.Start, $scope.link_controller); - $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.stream_controller); - $scope.rack_controller = new fsm.FSMController($scope, rack_fsm.Disable, $scope.group_controller); - $scope.site_controller = new fsm.FSMController($scope, site_fsm.Disable, $scope.rack_controller); - $scope.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.site_controller); - $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.buttons_controller); - $scope.app_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.time_controller); //App Toolbox Setup $scope.app_toolbox = new models.ToolBox(0, 'Process', 'app', 10, 200, 150, $scope.graph.height - 200 - 100); $scope.app_toolbox.spacing = 150; $scope.app_toolbox.enabled = false; $scope.app_toolbox_controller.toolbox = $scope.app_toolbox; $scope.app_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteProcess", new messages.PasteProcess(selected_item)); + $scope.first_channel.send("PasteProcess", new messages.PasteProcess(selected_item)); }; $scope.app_toolbox.items.push(new models.Process(0, 'BGP', 'process', 0, 0)); $scope.app_toolbox.items.push(new models.Process(0, 'OSPF', 'process', 0, 0)); @@ -129,7 +148,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.app_toolbox.items[i].icon = true; } - $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller); + $scope.inventory_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); //Inventory Toolbox Setup $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100); @@ -151,14 +170,14 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.inventory_toolbox_controller.toolbox = $scope.inventory_toolbox; $scope.inventory_toolbox_controller.remove_on_drop = true; $scope.inventory_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item)); + $scope.first_channel.send("PasteDevice", new messages.PasteDevice(selected_item)); }; for(i = 0; i < $scope.inventory_toolbox.items.length; i++) { $scope.inventory_toolbox.items[i].icon = true; } //End Inventory Toolbox Setup - $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller); + $scope.rack_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); //Rack Toolbox Setup $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 10, 200, 150, $scope.graph.height - 200 - 100); $scope.rack_toolbox.items.push(new models.Group(0, 'Rack3', 'rack', 0, 0, 200, 1000, 'false')); @@ -167,14 +186,14 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.rack_toolbox_controller.remove_on_drop = false; $scope.rack_toolbox_controller.toolbox = $scope.rack_toolbox; $scope.rack_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteRack", new messages.PasteRack(selected_item)); + $scope.first_channel.send("PasteRack", new messages.PasteRack(selected_item)); }; for(i = 0; i < $scope.rack_toolbox.items.length; i++) { $scope.rack_toolbox.items[i].icon = true; $scope.rack_toolbox.items[i].selected = false; } //End Rack Toolbox Setup - $scope.site_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.rack_toolbox_controller); + $scope.site_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); //Site Toolbox Setup $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 10, 200, 150, $scope.graph.height - 200 - 100); $scope.site_toolbox.items.push(new models.Group(0, 'Site3', 'site', 0, 0, 1000, 1000, 'false')); @@ -183,7 +202,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.site_toolbox_controller.remove_on_drop = false; $scope.site_toolbox_controller.toolbox = $scope.site_toolbox; $scope.site_toolbox_controller.dropped_action = function (selected_item) { - $scope.first_controller.handle_message("PasteSite", new messages.PasteSite(selected_item)); + $scope.first_channel.send("PasteSite", new messages.PasteSite(selected_item)); }; for(i = 0; i < $scope.site_toolbox.items.length; i++) { $scope.site_toolbox.items[i].icon = true; @@ -191,8 +210,58 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { } //End Site Toolbox Setup - $scope.mode_controller = new fsm.FSMController($scope, mode_fsm.Start, $scope.site_toolbox_controller); - $scope.first_controller = $scope.mode_controller; + $scope.mode_controller = new fsm.FSMController($scope, "mode_fsm", mode_fsm.Start, $scope); + + //Wire up the FSMs + $scope.view_controller.delegate_channel = new fsm.Channel($scope.view_controller, + $scope.hotkeys_controller, + $scope); + $scope.device_detail_controller.delegate_channel = new fsm.Channel($scope.device_detail_controller, + $scope.view_controller, + $scope); + $scope.move_controller.delegate_channel = new fsm.Channel($scope.move_controller, + $scope.device_detail_controller, + $scope); + $scope.link_controller.delegate_channel = new fsm.Channel($scope.link_controller, + $scope.move_controller, + $scope); + $scope.stream_controller.delegate_channel = new fsm.Channel($scope.stream_controller, + $scope.link_controller, + $scope); + $scope.group_controller.delegate_channel = new fsm.Channel($scope.group_controller, + $scope.stream_controller, + $scope); + $scope.rack_controller.delegate_channel = new fsm.Channel($scope.rack_controller, + $scope.group_controller, + $scope); + $scope.site_controller.delegate_channel = new fsm.Channel($scope.site_controller, + $scope.rack_controller, + $scope); + $scope.buttons_controller.delegate_channel = new fsm.Channel($scope.buttons_controller, + $scope.site_controller, + $scope); + $scope.time_controller.delegate_channel = new fsm.Channel($scope.time_controller, + $scope.buttons_controller, + $scope); + $scope.app_toolbox_controller.delegate_channel = new fsm.Channel($scope.app_toolbox_controller, + $scope.time_controller, + $scope); + $scope.inventory_toolbox_controller.delegate_channel = new fsm.Channel($scope.inventory_toolbox_controller, + $scope.app_toolbox_controller, + $scope); + $scope.rack_toolbox_controller.delegate_channel = new fsm.Channel($scope.rack_toolbox_controller, + $scope.inventory_toolbox_controller, + $scope); + $scope.site_toolbox_controller.delegate_channel = new fsm.Channel($scope.site_toolbox_controller, + $scope.rack_toolbox_controller, + $scope); + $scope.mode_controller.delegate_channel = new fsm.Channel($scope.mode_controller, + $scope.site_toolbox_controller, + $scope); + + $scope.first_channel = new fsm.Channel(null, + $scope.mode_controller, + $scope); var dids = $scope.device_id_seq; var mids = $scope.message_id_seq; @@ -401,7 +470,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseDown', $event); + $scope.first_channel.send('MouseDown', $event); $scope.onMouseDownResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -411,7 +480,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseUp', $event); + $scope.first_channel.send('MouseUp', $event); $scope.onMouseUpResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -436,7 +505,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.mouseX = $event.offsetX; $scope.mouseY = $event.offsetY; $scope.updateScaledXY(); - $scope.first_controller.handle_message('MouseMove', $event); + $scope.first_channel.send('MouseMove', $event); $scope.onMouseMoveResult = getMouseEventResult($event); $event.preventDefault(); }; @@ -457,7 +526,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey)); } $scope.last_event = $event; - $scope.first_controller.handle_message('MouseWheel', [$event, delta, deltaX, deltaY]); + $scope.first_channel.send('MouseWheel', [$event, delta, deltaX, deltaY]); event.preventDefault(); }; @@ -475,7 +544,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.last_event = $event; $scope.last_key = $event.key; $scope.last_key_code = $event.keyCode; - $scope.first_controller.handle_message('KeyDown', $event); + $scope.first_channel.send('KeyDown', $event); $scope.$apply(); $event.preventDefault(); }; @@ -504,7 +573,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.mouseY = $event.touches[0].screenY; $scope.updateScaledXY(); } - $scope.first_controller.handle_message('TouchStart', $event); + $scope.first_channel.send('TouchStart', $event); $scope.onTouchStartEvent = $event; $event.preventDefault(); }; @@ -519,7 +588,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { if ($scope.recording) { $scope.send_control_message(new messages.TouchEvent($scope.client_id, "touchend", touches)); } - $scope.first_controller.handle_message('TouchEnd', $event); + $scope.first_channel.send('TouchEnd', $event); $scope.onTouchEndEvent = $event; $event.preventDefault(); }; @@ -544,7 +613,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.updateScaledXY(); } - $scope.first_controller.handle_message('TouchMove', $event); + $scope.first_channel.send('TouchMove', $event); $scope.onTouchMoveEvent = $event; $event.preventDefault(); }; @@ -636,15 +705,15 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { // Buttons $scope.buttons = [ - new models.Button("BUTTON1", 10, 10, 90, 30, util.noop), - new models.Button("BUTTON1", 110, 10, 90, 30, util.noop), + new models.Button("BUTTON1", 10, 10, 90, 30, util.noop, $scope), + new models.Button("BUTTON1", 110, 10, 90, 30, util.noop, $scope), ]; var LAYERS_X = 160; $scope.layers = [ - new models.ToggleButton("TOGGLEBUTTON1", $scope.graph.width - LAYERS_X, 10, 150, 30, util.noop, util.noop, true), - new models.ToggleButton("TOGGLEBUTTON2", $scope.graph.width - LAYERS_X, 50, 150, 30, util.noop, util.noop, true), + new models.ToggleButton("TOGGLEBUTTON1", $scope.graph.width - LAYERS_X, 10, 150, 30, util.noop, util.noop, true, $scope), + new models.ToggleButton("TOGGLEBUTTON2", $scope.graph.width - LAYERS_X, 50, 150, 30, util.noop, util.noop, true, $scope), ]; var STENCIL_X = 10; @@ -652,8 +721,8 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { var STENCIL_SPACING = 40; $scope.stencils = [ - new models.Button("BUTTON3", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 0, 90, 30, util.noop), - new models.Button("BUTTON4", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 1, 90, 30, util.noop), + new models.Button("BUTTON3", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 0, 90, 30, util.noop, $scope), + new models.Button("BUTTON4", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 1, 90, 30, util.noop, $scope), ]; $scope.all_buttons = []; @@ -1326,7 +1395,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { $scope.control_socket.onmessage = function(message) { - $scope.first_controller.handle_message('Message', message); + $scope.first_channel.send('Message', message); $scope.$apply(); }; @@ -1391,7 +1460,7 @@ var NetworkWidgetsController = function($scope, $document, $location, $window) { for (i =0; i < $scope.initial_messages.length; i++) { console.log(['Inital message', $scope.initial_messages[i]]); - $scope.first_controller.handle_message($scope.initial_messages[i][0], $scope.initial_messages[i][1]); + $scope.first_channel.send($scope.initial_messages[i][0], $scope.initial_messages[i][1]); } $scope.updateScaledXY(); diff --git a/awx/network_ui/static/network_ui/src/rack.fsm.js b/awx/network_ui/static/network_ui/src/rack.fsm.js index 27dc705550..af6216329a 100644 --- a/awx/network_ui/static/network_ui/src/rack.fsm.js +++ b/awx/network_ui/static/network_ui/src/rack.fsm.js @@ -284,7 +284,7 @@ _Selected2.prototype.onCopySelected = function (controller) { _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { //controller.changeState(Ready); - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Selected2.prototype.onKeyDown.transitions = ['Ready']; @@ -407,7 +407,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { if (selected) { controller.changeState(Selected1); } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Ready.prototype.onMouseDown.transitions = ['Selected1']; diff --git a/awx/network_ui/static/network_ui/src/site.fsm.js b/awx/network_ui/static/network_ui/src/site.fsm.js index efeec22245..b8a120c5ee 100644 --- a/awx/network_ui/static/network_ui/src/site.fsm.js +++ b/awx/network_ui/static/network_ui/src/site.fsm.js @@ -367,7 +367,7 @@ _Selected2.prototype.onCopySelected = function (controller) { _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { //controller.changeState(Ready); - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); }; _Selected2.prototype.onKeyDown.transitions = ['Ready']; @@ -490,7 +490,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { if (selected) { controller.changeState(Selected1); } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Ready.prototype.onMouseDown.transitions = ['Selected1']; diff --git a/awx/network_ui/static/network_ui/src/time.js b/awx/network_ui/static/network_ui/src/time.js index 4c985d74e3..349a606791 100644 --- a/awx/network_ui/static/network_ui/src/time.js +++ b/awx/network_ui/static/network_ui/src/time.js @@ -195,7 +195,7 @@ _Past.prototype.onMouseWheel = function (controller, msg_type, message) { this.redo(controller); } } else { - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); } }; @@ -218,7 +218,7 @@ _Past.prototype.onKeyDown = function(controller, msg_type, $event) { this.redo(controller); return; } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Past.prototype.onKeyDown.transitions = ['Present']; @@ -504,7 +504,7 @@ _Present.prototype.onMouseWheel = function (controller, msg_type, message) { this.undo(controller); } } else { - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); } }; @@ -521,7 +521,7 @@ _Present.prototype.onKeyDown = function(controller, msg_type, $event) { this.undo(controller); return; } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Present.prototype.onKeyDown.transitions = ['Past']; diff --git a/awx/network_ui/static/network_ui/src/toolbox.fsm.js b/awx/network_ui/static/network_ui/src/toolbox.fsm.js index 2fc2bed471..a4a226fc1f 100644 --- a/awx/network_ui/static/network_ui/src/toolbox.fsm.js +++ b/awx/network_ui/static/network_ui/src/toolbox.fsm.js @@ -145,7 +145,7 @@ _Selecting.prototype.onMouseDown = function (controller) { toolbox.selected_item.x = toolbox.x + toolbox.width/2; toolbox.selected_item.y = selected_item * toolbox.spacing + toolbox.y + toolbox.scroll_offset + toolbox.spacing/2; controller.scope.clear_selections(); - controller.scope.first_controller.handle_message("UnselectAll", {}); + controller.scope.first_channel.send("UnselectAll", {}); controller.changeState(Selected); } else { toolbox.selected_item = null; @@ -171,7 +171,7 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { controller.handle_message(msg_type, $event); } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Ready.prototype.onMouseDown.transitions = ['Selecting']; @@ -188,7 +188,7 @@ _Ready.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.handle_message(msg_type, $event); } else { - controller.next_controller.handle_message(msg_type, $event); + controller.delegate_channel.send(msg_type, $event); } }; _Ready.prototype.onMouseWheel.transitions = ['Scrolling']; @@ -196,7 +196,7 @@ _Ready.prototype.onMouseWheel.transitions = ['Scrolling']; _Ready.prototype.onToggleToolbox = function (controller, msg_type, message) { controller.changeState(OffScreen); - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); }; _Ready.prototype.onToggleToolbox.transitions = ['OffScreen']; @@ -256,7 +256,7 @@ _Move.prototype.onMouseMove = function (controller) { _OffScreen.prototype.onToggleToolbox = function (controller, msg_type, message) { controller.changeState(Ready); - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); }; _OffScreen.prototype.onToggleToolbox.transitions = ['Ready']; @@ -298,7 +298,7 @@ _OffScreen2.prototype.start = function (controller) { _OffScreen2.prototype.onToggleToolbox = function (controller, msg_type, message) { controller.changeState(Disabled); - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); }; _OffScreen2.prototype.onToggleToolbox.transitions = ['Disabled']; @@ -327,6 +327,6 @@ _Disabled.prototype.end = function (controller) { _Disabled.prototype.onToggleToolbox = function (controller, msg_type, message) { controller.changeState(OffScreen2); - controller.next_controller.handle_message(msg_type, message); + controller.delegate_channel.send(msg_type, message); }; _Disabled.prototype.onToggleToolbox.transitions = ['OffScreen2']; diff --git a/awx/network_ui/urls.py b/awx/network_ui/urls.py index 2d3c7b9906..5f4f885cdf 100644 --- a/awx/network_ui/urls.py +++ b/awx/network_ui/urls.py @@ -7,6 +7,7 @@ import awx.network_ui.routing app_name = 'network_ui' urlpatterns = [ + url(r'^download_trace$', views.download_trace, name='download_trace'), url(r'^topology.json$', views.json_topology_data, name='json_topology_data'), url(r'^topology.yaml$', views.yaml_topology_data, name='json_topology_data'), url(r'^$', views.index, name='index'), diff --git a/awx/network_ui/views.py b/awx/network_ui/views.py index 9c72925e63..1f52179c52 100644 --- a/awx/network_ui/views.py +++ b/awx/network_ui/views.py @@ -6,7 +6,7 @@ import yaml # Create your views here. -from .models import Topology +from .models import Topology, FSMTrace from .serializers import topology_data @@ -35,3 +35,24 @@ def yaml_topology_data(request): else: return HttpResponseBadRequest(form.errors) + +class FSMTraceForm(forms.Form): + topology_id = forms.IntegerField() + trace_id = forms.IntegerField() + client_id = forms.IntegerField() + + +def download_trace(request): + form = FSMTraceForm(request.GET) + if form.is_valid(): + topology_id = form.cleaned_data['topology_id'] + trace_id = form.cleaned_data['trace_id'] + client_id = form.cleaned_data['client_id'] + data = list(FSMTrace.objects.filter(trace_session_id=trace_id, + client_id=client_id).order_by('order').values()) + response = HttpResponse(yaml.safe_dump(data, default_flow_style=False), + content_type="application/force-download") + response['Content-Disposition'] = 'attachment; filename="trace_{0}_{1}_{2}.yml"'.format(topology_id, client_id, trace_id) + return response + else: + return HttpResponse(form.errors)