Skip to content

Commit c4fe5e0

Browse files
authored
docs: misc improved docs, added fetching raw events section (#133)
* fix: update reference of `hostname` to `client_hostname` * chore: remove unused import * docs: update versions * docs: add a link to query page * docs: create raw_events.py * docs: add raw data fetching * docs: minor edit * docs: comment smartertime importer is deprecated * docs: additional comments on client.rs * docs: add wakatime importer * chore: remove unused import in client.py * fix: updates to use tuple timeperiods * docs: replace renaming events with a redaction use case * docs: better phrasing on aw-import-screentime
1 parent 5dac898 commit c4fe5e0

File tree

8 files changed

+100
-18
lines changed

8 files changed

+100
-18
lines changed

src/api/rest.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,4 @@ The `heartbeat <heartbeats>` API is one of the most useful endpoints for writing
9595
9696
Query API
9797
~~~~~~~~~~~~~
98-
99-
**TODO: Add link to writing queries once that page is done**
98+
`Writing Queries <./../examples/querying-data.html>`_

src/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@
8383
# built documents.
8484
#
8585
# The short X.Y version.
86-
version = "0.11"
86+
version = "0.13"
8787

8888
# The full version, including alpha/beta/rc tags.
8989
# TODO: Get from aw_server version
90-
release = "v0.11.0"
90+
release = "v0.13.1"
9191

9292
# The language for content autogenerated by Sphinx. Refer to documentation
9393
# for a list of supported languages.

src/examples/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python3
22

33
from time import sleep
4-
from datetime import datetime, timedelta, timezone
4+
from datetime import datetime, timezone
55

66
from aw_core.models import Event
77
from aw_client import ActivityWatchClient

src/examples/client.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ async fn main() {
3333
let bucket_id = format!("test-client-bucket_{}", aw_client.hostname);
3434
let event_type = "dummy_data".to_string();
3535

36+
// Note that in a real application, you would want to handle these errors
3637
create_bucket(&aw_client, bucket_id.clone(), event_type)
3738
.await
3839
.unwrap();
@@ -60,6 +61,7 @@ async fn main() {
6061
.unwrap();
6162

6263
// Sleep a second until next heartbeat (eventually drifts due to time spent in the loop)
64+
// You could use wait on tokio intervals to avoid drift
6365
tokio::time::sleep(tokio::time::Duration::from_secs_f64(sleeptime)).await;
6466
}
6567

src/examples/query_client.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env python3
22

3-
from time import sleep
43
from datetime import datetime, timedelta, timezone
54

65
from aw_core.models import Event
@@ -14,10 +13,15 @@
1413
start = now
1514

1615
query = "RETURN=0;"
17-
res = client.query(query, "1970-01-01", "2100-01-01")
16+
start_date = datetime(1970, 1, 1, tzinfo=timezone.utc)
17+
end_date = datetime(2100, 1, 1, tzinfo=timezone.utc)
18+
19+
# Note that the timeperiods are a list of tuples
20+
timeperiods = [(start_date, end_date)]
21+
res = client.query(query, timeperiods=timeperiods)
1822
print(res) # Should print 0
1923

20-
bucket_id = "{}_{}".format("test-client-bucket", client.hostname)
24+
bucket_id = "{}_{}".format("test-client-bucket", client.client_hostname)
2125
event_type = "dummydata"
2226
client.create_bucket(bucket_id, event_type="test")
2327

@@ -34,22 +38,23 @@ def insert_events(label: str, count: int):
3438

3539
insert_events("a", 5)
3640

37-
query = "RETURN = query_bucket('{}');".format(bucket_id)
41+
query = 'RETURN = query_bucket("{}");'.format(bucket_id)
3842

39-
res = client.query(query, "1970", "2100")
43+
res = client.query(query,timeperiods=timeperiods)
4044
print(res) # Should print the last 5 events
4145

42-
res = client.query(query, start + timedelta(seconds=1), now - timedelta(seconds=2))
46+
timeperiods_2 = [(start+timedelta(seconds=1), now-timedelta(seconds=2))]
47+
res = client.query(query, timeperiods=timeperiods_2)
4348
print(res) # Should print three events
4449

4550
insert_events("b", 10)
4651

4752
query = """
48-
events = query_bucket('{}');
49-
merged_events = merge_events_by_keys(events, 'label');
53+
events = query_bucket("{}");
54+
merged_events = merge_events_by_keys(events, ["label"]);
5055
RETURN=merged_events;
5156
""".format(bucket_id)
52-
res = client.query(query, "1970", "2100")
57+
res = client.query(query, timeperiods=timeperiods)
5358
# Should print two merged events
5459
# Event "a" with a duration of 5s and event "b" with a duration of 10s
5560
print(res)

src/examples/querying-data.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ Example including aw-client:
8080

8181
Fetching Raw Events
8282
-------------------
83+
It is possible to fetch the raw events from a bucket. This is useful if you want to do your own analysis on the data, or if you want to use the aw-analysis library to do transformations on the data.
8384

84-
**TODO:** Write this section
85+
Example fetching raw events from the "aw-watcher-window_" bucket:
86+
This is an example that you can run in a Python to fetch raw events posted by the window watcher.
87+
The scripts sums the time spent on each window title and showcases a data redaction use case.
8588

86-
`Bucket REST API <./rest.html#get-events>`_
89+
.. literalinclude:: raw_events.py
90+
91+
92+
.. TODO `Bucket REST API <./rest.html#get-events>`_

src/examples/raw_events.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
from aw_client import ActivityWatchClient
3+
from aw_core.models import Event
4+
import re
5+
from typing import Pattern, cast, List, Set
6+
from copy import deepcopy
7+
8+
client = ActivityWatchClient("test-client", testing=True)
9+
10+
# get the buckets
11+
buckets = client.get_buckets()
12+
13+
bucket_id = "{}_{}".format("aw-watcher-window", client.client_hostname)
14+
15+
# fetches 1000 events from the bucket
16+
events = client.get_events(bucket_id, limit=1000)
17+
18+
# sum the time spent on each app
19+
time_spent = dict()
20+
for event in events:
21+
app = event.data["app"]
22+
if app in time_spent:
23+
time_spent[app] += event.duration
24+
else:
25+
time_spent[app] = event.duration
26+
27+
print(time_spent)
28+
29+
# sensitive data pattern
30+
pattern = re.compile(r"Binance|Metamask|TrustWallet|Trust Wallet")
31+
32+
# what to replace sensitive data with
33+
REDACTED = "REDACTED"
34+
35+
def _redact_event(e: Event, pattern: Pattern) -> Event:
36+
e = deepcopy(e)
37+
for k, v in e.data.items():
38+
if isinstance(v, str):
39+
if pattern.findall(v.lower()):
40+
e.data[k] = REDACTED
41+
return e
42+
43+
def _find_sensitive(el: List[Event], pattern: Pattern) -> Set:
44+
sensitive_ids = set()
45+
for e in el:
46+
if _check_event(e, pattern):
47+
sensitive_ids.add(e.id)
48+
return sensitive_ids
49+
50+
def _check_event(e: Event, pattern: Pattern) -> bool:
51+
for k, v in e.data.items():
52+
if isinstance(v, str):
53+
if pattern.findall(v.lower()):
54+
return True
55+
return False
56+
57+
sensitive_ids = _find_sensitive(events, pattern)
58+
for e in events:
59+
print(f"Event id: {e.id}")
60+
if e.id in sensitive_ids:
61+
e_before = e
62+
e = _redact_event(e, pattern)
63+
print(f"\nData before: {e_before.data}")
64+
print(f"Data after: {e.data}")
65+
66+
client.delete_event(bucket_id, cast(int, e_before.id))
67+
client.insert_event(bucket_id, e)
68+
print("Redacted event")

src/importers.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ Importers
44
ActivityWatch can't track everything, so sometimes you might want to import data from another source.
55

66
- :gh-aw:`aw-import-ical`, supports importing from ``.ical`` files or syncing with Google Calendar.
7-
- :gh-aw:`aw-importer-smartertime`, imports from `smartertime`_ (Android time tracker).
8-
- :gh-aw:`aw-import-screentime`, attempt at importing from macOS's Screen Time (and potentially iOS through syncing)
7+
- :gh-aw:`aw-importer-smartertime`, imports from `smartertime`_ Useful for importing Android screentime data.(Note ActivityWatch also has an Android app :gh-aw:`aw-android`)
8+
- :gh-aw:`aw-import-screentime`, attempt at importing from macOS's Screen Time (and potentially iOS through syncing).
9+
- :gh:`brayo-pip/aw-import-wakatime`, imports from `Wakatime`_ (For tracking time spent programming).
910

1011

1112
.. _smartertime: https://play.google.com/store/apps/details?id=com.smartertime&hl=en
13+
.. _Wakatime: https://wakatime.com/

0 commit comments

Comments
 (0)