Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
8ac5676
Added native_chrome_extension folder
May 5, 2023
5c7f573
Implementing Issue #83
May 5, 2023
1572d45
Minor changes for the .sh installation script
May 6, 2023
224f321
Implementing Scrubbing Issue #47
May 6, 2023
5f3dd57
remove native folder
May 6, 2023
4912397
add native folder
May 6, 2023
114b4cc
Add briwer.py, native-manifest.json,
May 6, 2023
afcb296
remove uneccessary commits
May 7, 2023
8d65084
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 7, 2023
84ec702
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 7, 2023
4a9cd54
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 10, 2023
1c3544a
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 12, 2023
958efaa
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 16, 2023
10a55f6
Progress on Issue #51
May 19, 2023
8a2a11f
Add nativemessaging
May 22, 2023
76e45aa
Merge branch 'MLDSAI:main' into issue51
KrishPatel13 May 23, 2023
daac09e
remove all
May 23, 2023
8a719a9
test_extension files
May 24, 2023
e6b1e9f
browser to chrome
May 24, 2023
8a86f49
browser -> chrome
May 24, 2023
bfeb34d
test native applicatoin
May 24, 2023
7a48fa9
fixes
May 24, 2023
7fbe220
add bat in antive json
May 26, 2023
a3dc610
resolving merge conflicts
Jun 2, 2023
a0afc90
Merge pull request #7 from MLDSAI/main
KrishPatel13 Jun 2, 2023
8e93a83
attempting ping pong example on chrome
Jun 5, 2023
34f237c
ping pong example on chrome
Jun 6, 2023
bd10fa8
Merge branch 'MLDSAI:main' into test_extension
KrishPatel13 Jun 7, 2023
64df009
New Tab Listner
Jun 7, 2023
c0e4e48
add content script for accessing document object
Jun 7, 2023
b484f7e
remove old code
Jun 7, 2023
2847d1a
Now, the extensions sends
Jun 7, 2023
aa44f38
Mutation Observer in content.js
Jun 30, 2023
3acd453
working DOM Mutation Observer COde
Jun 30, 2023
4efc218
Chrome Extension - Progress:
Jun 30, 2023
062e5af
add link for the system diagram
Jun 30, 2023
3eda05f
Update:
Jun 30, 2023
6413463
add ignoreAtributes
Jul 6, 2023
0212e32
add hostPermissions
Jul 6, 2023
b621923
Now the Extensions sends:
Jul 6, 2023
c18f613
before test code
Jul 6, 2023
0562292
resolve merge conflicts
Jul 6, 2023
5e513dd
Merge pull request #357 from OpenAdaptAI/main
KrishPatel13 Jul 6, 2023
3b7f2b7
add serve.py t o show pipe is working normally but not
Jul 6, 2023
9a7c29c
working Extension demo with sockets
Jul 7, 2023
1dff338
add ToDO
Jul 7, 2023
59a1029
add todos
Jul 7, 2023
863dee3
add Todos
Jul 8, 2023
8b4ad90
format Js files
Jul 8, 2023
f761da7
add documentatoin
Jul 8, 2023
56a320e
minor changes in formatting
Jul 8, 2023
346772e
format multiple files
Jul 8, 2023
aea191b
format pylint browser
Jul 8, 2023
75b776f
add read_browser_events and browser evnet queues
Jul 10, 2023
1efa3e4
add browser writer function
Jul 10, 2023
db1c249
changes to the extension
Jul 10, 2023
1aade8e
add browser events in multiple files
Jul 11, 2023
ba220be
add missing browser events
Jul 11, 2023
598ee36
add browser_event_dict in visualize.py
Jul 11, 2023
7ec2567
fix: socket_client script on
Jul 12, 2023
562d240
add code for sockets.py and make related changes
Jul 13, 2023
e59e6a6
merge main to continue_extension
Jul 13, 2023
5fc3859
update the sockets.py script
Jul 13, 2023
220d796
Merge pull request #382 from OpenAdaptAI/main
KrishPatel13 Jul 13, 2023
b4bb984
rename to mock_client
Jul 14, 2023
3e68d62
fix: server send message
Jul 14, 2023
11bce46
now the extensoin works using the sockets.py
Jul 14, 2023
f13f885
update browser.py to use sockets.py
Jul 17, 2023
fcd7428
now the browser.py and mock_client
Jul 17, 2023
9aec8b9
add mock_client code to record
Jul 17, 2023
056087f
try to fix errors during record eith extension
Jul 17, 2023
c313199
try to fix communication closed
Jul 17, 2023
de76ab1
try to fix error :-
Jul 18, 2023
bb1b082
Merge pull request #399 from OpenAdaptAI/main
KrishPatel13 Jul 18, 2023
109b620
attempt to observe
Jul 19, 2023
06d7ed8
try to fix the infinite running server
Jul 19, 2023
c38c6cc
Merge branch 'main' into continue_extension
KrishPatel13 Jul 27, 2023
d2e4301
Create browser.sh
0dm Jul 28, 2023
b33f6a0
mac version
0dm Jul 31, 2023
14f3bad
merge main
0dm Aug 21, 2023
1d69344
write documentstates to db and visualize
0dm Aug 22, 2023
c44ca0a
remove duplicate messages, add exception handling,
0dm Aug 24, 2023
791e3ee
xy + input value + debounce
0dm Aug 24, 2023
09cab02
add nativemessaginghost install script
0dm Aug 24, 2023
781d531
Create view_messages_table.py
0dm Aug 25, 2023
ad68e18
add comment
0dm Aug 25, 2023
9f2932e
Update browser.py
0dm Aug 25, 2023
c501f62
Merge remote-tracking branch 'upstream/main' into continue_extension
0dm Aug 25, 2023
33718cf
add mutationObserverImplementation
0dm Aug 28, 2023
7dd2188
work on socket
0dm Aug 28, 2023
a80004c
fixed socket
0dm Aug 28, 2023
3a468f8
Update browser.py
0dm Aug 28, 2023
478e325
update windows path & clean
0dm Aug 28, 2023
46bff0e
Merge remote-tracking branch 'upstream/main' into continue_extension
0dm Aug 28, 2023
4b8bf27
styling
0dm Aug 28, 2023
1a74aa1
more styling
0dm Aug 28, 2023
bc2d6a6
delete init
0dm Aug 28, 2023
a5daeb4
rename directory
0dm Aug 28, 2023
59be3e4
disable socket for now
0dm Aug 28, 2023
ac1ac8d
use last message
0dm Aug 28, 2023
bbc4a3a
add elements
0dm Aug 28, 2023
c67975b
progress on recording + db table
0dm Aug 31, 2023
4759725
Create 1a19ce257672_add_browserevent_message.py
0dm Aug 31, 2023
cafc053
fix error in browser
0dm Sep 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ cache
*.db
*.db-journal

*.html

# VSCode
.VSCode
.vsCode
Expand Down
49 changes: 49 additions & 0 deletions alembic/versions/1a19ce257672_add_browserevent_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""add BrowserEvent.message

Revision ID: 1a19ce257672
Revises: 8713b142f5de
Create Date: 2023-08-28 17:01:07.703670

"""
import sqlalchemy as sa

from alembic import op
import openadapt

# revision identifiers, used by Alembic.
revision = "1a19ce257672"
down_revision = "8713b142f5de"
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"browser_event",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column(
"recording_timestamp",
openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False),
nullable=True,
),
sa.Column("message", sa.JSON(), nullable=True),
sa.Column(
"timestamp",
openadapt.models.ForceFloat(precision=10, scale=2, asdecimal=False),
nullable=True,
),
sa.ForeignKeyConstraint(
["recording_timestamp"],
["recording.timestamp"],
name=op.f("fk_browser_event_recording_timestamp_recording"),
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_browser_event")),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("browser_event")
# ### end Alembic commands ###
54 changes: 54 additions & 0 deletions chrome/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @file background.js
* @description This file is responsible for communicating with the native
* messaging host and the content script.
* @see https://docs.google.com/presentation/d/106AXW3sBe7-7E-zIggnMnaUKUXWAj_aAuSxBspTDcGk/edit#slide=id.p
*/

const hostName = "openadapt";
var port = null; // Native Messaging port
var lastMsg = null;

/*
* Handle received messages from browser.js
*/
function onReceived(response) {
console.log(response);
}

function onDisconnected() {
msg = "Failed to connect: " + chrome.runtime.lastError.message; // silence error
port = null;
}

function connect() {
port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(onReceived);
port.onDisconnect.addListener(onDisconnected);
}

/*
* Message listener for content script
*/
function messageListener(message, sender, sendResponse) {
const timestampThreshold = 30; // arbitrary threshold in milliseconds

try {
if (lastMsg !== null) {
if (
Math.abs(message.timestamp - lastMsg.timestamp) < timestampThreshold &&
message.tagName === lastMsg.tagName &&
message.action === lastMsg.action
) {
return;
}
}
console.log({ message, sender, sendResponse });
port.postMessage(message); // send to browser.py (native messaging host)
lastMsg = message;
} catch (e) {
connect();
}
}
connect();
chrome.runtime.onMessage.addListener(messageListener);
3 changes: 3 additions & 0 deletions chrome/browser.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off

python -u "P:\\OpenAdapt AI - MLDS AI\\cloned_repo\\OpenAdapt\\chrome\\browser.py"
113 changes: 113 additions & 0 deletions chrome/browser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python3 # noqa: D205

"""Script for communicating with the browser extension. # noqa: D205 D415
Usage:
See `native_chrome_extension/browser.bat`.
"""

# Note that running python with the `-u` flag is required on Windows,
# in order to ensure that stdin and stdout are opened in binary, rather
# than text, mode.

import json
import sqlite3
import struct
import sys

from openadapt import config, sockets

SOCKETS = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this ever be False?

DBG_DATABASE = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please clarify what this is for?



def get_message() -> dict:
"""Read a message from stdin and decode it.

Returns:
A dictionary representing the decoded message.
"""
raw_length = sys.stdin.buffer.read(4)
if len(raw_length) == 0:
sys.exit(0)
message_length = struct.unpack("@I", raw_length)[0]
message = sys.stdin.buffer.read(message_length).decode("utf-8")
return json.loads(message)


def encode_message(message_content: any) -> dict:
"""Encode a message for transmission, given its content.

Args:
message_content: The content of the message to be encoded.

Returns:
A dictionary containing the encoded message.
"""
# https://docs.python.org/3/library/json.html#basic-usage
# To get the most compact JSON representation, you should specify
# (',', ':') to eliminate whitespace.
# We want the most compact representation because the browser rejects
# messages that exceed 1 MB.
encoded_content = json.dumps(message_content, separators=(",", ":")).encode("utf-8")
encoded_length = struct.pack("@I", len(encoded_content))
return {"length": encoded_length, "content": encoded_content}


def send_message(encoded_message: dict) -> None:
"""Send an encoded message to stdout.

Args:
encoded_message: The encoded message to be sent.
"""
sys.stdout.buffer.write(encoded_message["length"])
sys.stdout.buffer.write(encoded_message["content"])
sys.stdout.buffer.flush()


def send_message_to_client(conn: sockets.Connection, message: dict) -> None:
"""Send a message to the client.

Args:
conn: The connection to the client.
message: The message to be sent.
"""
try:
conn.send(message)
except Exception as exc:
print(f"Error sending message to client: {exc}")


def main() -> None:
"""Main function."""
if DBG_DATABASE:
db_conn = sqlite3.connect("messages.db")
c = db_conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message TEXT NOT NULL
)
""")
if SOCKETS:
conn = sockets.create_server_connection(config.SOCKET_PORT)
while True:
if SOCKETS and conn.closed:
conn = sockets.create_server_connection(config.SOCKET_PORT)
message = get_message()

# Log the message to the database
if DBG_DATABASE:
c.execute(
"INSERT INTO messages (message) VALUES (?)", (json.dumps(message),)
)
db_conn.commit()
response = {"message": "Data received and logged successfully!"}
if message:
encoded_response = encode_message(response)
send_message(encoded_response)
if SOCKETS:
send_message_to_client(conn, message)


if __name__ == "__main__":
main()
124 changes: 124 additions & 0 deletions chrome/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* @file content.js
* @description This file is injected into the web page and is responsible for
* capturing DOM changes and sending them to the background script.
*/

let logged = false;
let ignoreAttributes = new Set();
const elements = {};

/*
* Function to send a message to the background script
*/
function sendMessageToBackgroundScript(message) {
chrome.runtime.sendMessage(message);
}

/*
* Function to capture initial document state and
* send it to the background script
*/
function captureDocumentState() {
const documentBody = document.body.outerHTML;
const documentHead = document.head.outerHTML;
const page_url = window.location.href;

sendMessageToBackgroundScript({
action: "captureDocumentState",
documentBody: documentBody,
documentHead: documentHead,
elements: elements,
url: page_url,
timestamp: Date.now(),
});
}

function handleElementClick(event) {
const element = event.target;
const tagName = element.tagName;
const { x, y } = elements[element.id] || {};
const value = elements[element.id]?.value || "";
const attributes = {};

for (const attr of element.attributes) {
attributes[attr.name] = attr.value;
}

sendMessageToBackgroundScript({
action: "elementClicked",
tagName: tagName,
attributes: attributes,
x: x,
y: y,
value: value,
url: window.location.href,
timestamp: Date.now(),
});
}

function debounce(func, delay) {
let timerId;
return function (...args) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
func.apply(this, args);
timerId = null;
}, delay);
};
}

function handleDebouncedInput(event) {
const element = event.target;
const { x, y } = elements[element.id];
const value = elements[element.id].element.value;
const tagName = element.tagName;
const attributes = {};

for (const attr of element.attributes) {
attributes[attr.name] = attr.value;
}

sendMessageToBackgroundScript({
action: "elementInput",
tagName: tagName,
attributes: attributes,
x: x,
y: y,
value: value,
url: window.location.href,
timestamp: Date.now(),
});
}

const debouncedInputHandler = debounce(handleDebouncedInput, 500);

function handleElementInput(event) {
debouncedInputHandler(event);
}

function addElement(element) {
const rect = element.getBoundingClientRect();
const x = rect.left + window.scrollX;
const y = rect.top + window.scrollY;
const value = element.value;
if (!element.id) {
element.id = element.tagName + "_" + x + "_" + y;
}
elements[element.id] = { element, x, y, value };
element.addEventListener("click", handleElementClick);
element.addEventListener("input", debounce(handleDebouncedInput, 500));
}

function addEventListeners() {
const elements = document.getElementsByTagName("*");

for (const element of elements) {
addElement(element);
}
}

addEventListeners();
captureDocumentState();
Loading