Skip to content

Commit

Permalink
feat(docs, cli): use new core
Browse files Browse the repository at this point in the history
  • Loading branch information
cathaypacific8747 committed Jun 18, 2024
1 parent 6e14a66 commit 3868152
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 120 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
data/research/index.js
data/research/vendor.js
fr24.conf

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
1 change: 1 addition & 0 deletions data/research/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.js
2 changes: 1 addition & 1 deletion docs/usage/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ An example of it can be found at [`fr24.example.conf`](https://github.com/cathay
```

[^1]: When the [FR24 class][fr24.core.FR24]' context is entered, a request is automatically made to retrieve the OAuth tokens
[^2]: `fr24_token` should be a JWT with the `exp` claim in a few months, while `fr24_subscription_key` should be the shorter one. `fr24_token` is optional but live feed will fail without it.
[^2]: `fr24_token` should be a JWT with the `exp` claim in a month, while `fr24_subscription_key` should be the shorter one. `fr24_token` is optional but live feed will fail without it. Be sure to update the JWT in time.
108 changes: 93 additions & 15 deletions docs/usage/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@
=== "Output"

```
Usage: fr24 [OPTIONS] COMMAND [ARGS]...

╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy │
│ it or customize the installation. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ auth Commands for authentication │
│ dirs Shows relevant directories │
│ feed Fetches current livefeed / playback of live feed at a given time │
│ tui Starts the TUI │
╰──────────────────────────────────────────────────────────────────────────────╯
Usage: fr24 [OPTIONS] COMMAND [ARGS]...

╭─ Options ────────────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or │
│ customize the installation. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────────────╮
│ auth Commands for authentication │
│ dirs Shows relevant directories │
│ feed Fetches current livefeed / playback of live feed at a given time │
│ flight-list Fetches flight list for the given registration or flight number │
│ playback Fetches historical track playback data for the given flight │
│ tui Starts the TUI │
╰──────────────────────────────────────────────────────────────────────────────────────╯
```

- Dump the current (or playback of) live feed in a tidy parquet file:
Expand All @@ -33,7 +35,8 @@
```
fr24 feed
fr24 feed --timestamp 1702839380
fr24 feed --time 2023-12-17T18:56:00
fr24 feed --timestamp 2023-12-17T18:56:00
fr24 feed --help
```

=== "Output"
Expand Down Expand Up @@ -68,6 +71,81 @@
└──────────────────────────────────────────────────────────────────────┘
```

- Dump the

=== "Shell"

```
fr24 flight-list --reg B-HPB
fr24 flight-list --flight CX488
fr24 flight-list --help
```

=== "Output"

```command
$ fr24 flight-list --reg B-HPB
Success: Saved 10 rows (1290 bytes) to /home/user/.cache/fr24/flight_list/reg/B-HPB.parquet.

$ duckdb -c "describe select * from '/home/user/.cache/fr24/flight_list/reg/B-HPB.parquet';"

```
┌──────────────┬─────────────┬─────────┬─────────┬─────────┬─────────┐
│ column_name │ column_type │ null │ key │ default │ extra │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │
├──────────────┼─────────────┼─────────┼─────────┼─────────┼─────────┤
│ flight_id │ UBIGINT │ YES │ │ │ │
│ number │ VARCHAR │ YES │ │ │ │
│ callsign │ VARCHAR │ YES │ │ │ │
│ icao24 │ UINTEGER │ YES │ │ │ │
│ registration │ VARCHAR │ YES │ │ │ │
│ typecode │ VARCHAR │ YES │ │ │ │
│ origin │ VARCHAR │ YES │ │ │ │
│ destination │ VARCHAR │ YES │ │ │ │
│ status │ VARCHAR │ YES │ │ │ │
│ STOD │ TIMESTAMP │ YES │ │ │ │
│ ETOD │ TIMESTAMP │ YES │ │ │ │
│ ATOD │ TIMESTAMP │ YES │ │ │ │
│ STOA │ TIMESTAMP │ YES │ │ │ │
│ ETOA │ TIMESTAMP │ YES │ │ │ │
│ ATOA │ TIMESTAMP │ YES │ │ │ │
├──────────────┴─────────────┴─────────┴─────────┴─────────┴─────────┤
│ 15 rows 6 columns │
└────────────────────────────────────────────────────────────────────┘
```

- Dump the historical track playback data for the given flight

=== "Shell"

```
fr24 playback 2d81a27
fr24 playback --help
```

=== "Output"

```command
$ fr24 playback 2d81a27
Success: Saved 62 rows (4162 bytes) to /home/user/.cache/fr24/playback/2d81a27.parquet.

$ duckdb -c "describe select * from '/home/user/.cache/fr24/playback/2d81a27.parquet'"
┌────────────────┬───────────────────────────────┬─────────┬─────────┬─────────┬─────────┐
│ column_name │ column_type │ null │ key │ default │ extra │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │
├────────────────┼───────────────────────────────┼─────────┼─────────┼─────────┼─────────┤
│ timestamp │ UINTEGER │ YES │ │ │ │
│ latitude │ FLOAT │ YES │ │ │ │
│ longitude │ FLOAT │ YES │ │ │ │
│ altitude │ INTEGER │ YES │ │ │ │
│ ground_speed │ SMALLINT │ YES │ │ │ │
│ vertical_speed │ SMALLINT │ YES │ │ │ │
│ heading │ SMALLINT │ YES │ │ │ │
│ squawk │ USMALLINT │ YES │ │ │ │
│ ems │ STRUCT("timestamp" UINTEGER… │ YES │ │ │ │
└────────────────┴───────────────────────────────┴─────────┴─────────┴─────────┴─────────┘
```

- TUI:

```
Expand Down
10 changes: 5 additions & 5 deletions docs/usage/examples.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
You can find even more usage examples under [`tests/`](https://github.com/cathaypacific8747/fr24/tree/master/tests).

[Skip to lower level functions](#functional-style)
[Skip to lower level functions](#lower-level-functions)

## `FR24` class

Expand Down Expand Up @@ -90,8 +90,8 @@ Saves trajectory data to disk, reads the track and metadata from it.
```py
--8<-- "docs/usage/scripts/11_playback.py:metadata0"
```
<!-- ### Live Feed
*API reference: [fr24.core.FR24.livefeed][], [fr24.core.LiveFeedAPI.fetch][]*
### Live Feed
*API reference: [fr24.core.LiveFeedService][], [fr24.core.LiveFeedService.fetch][]*

#### Live
This example is covered in detail in the [quickstart](./quickstart.md).
Expand Down Expand Up @@ -129,9 +129,9 @@ Fetches the live feed three days ago.

```
--8<-- "docs/usage/scripts/12_livefeed.py:df2"
``` -->
```

## Functional Style
## Lower-level functions
### Flight list
*API Reference: [fr24.history.flight_list][], [fr24.history.flight_list_df][]*

Expand Down
8 changes: 3 additions & 5 deletions docs/usage/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ However, the [FR24][fr24.core.FR24] class provides a convenient wrapper around t

Each service has its own async `.fetch()` method to retrieve raw data from the API. `.to_arrow()` can then be used to transform to an Apache Arrow table, and used to perform caching and downstream `pandas` operations.

Here is an example for using the [**Live Feed**][fr24.core.FR24.livefeed] service:
Here is an example for using the [**Live Feed**][fr24.core.LiveFeedService] service:

### Initialisation

Expand Down Expand Up @@ -114,7 +114,7 @@ The `async with` statement ensures that it is properly authenticated by calling
You can retrieve:

- the [context related to the request][fr24.types.core.LiveFeedContext] with `response.ctx`;
- the raw JSON response as a list of [typed dictionaries][fr24.types.cache.LiveFeedRecord] with `response.data`.
- the [raw JSON response][fr24.types.cache.LiveFeedRecord] as a list of typed dictionaries with `response.data`.

### Transformation to Arrow

Expand Down Expand Up @@ -215,9 +215,7 @@ These directories are created automatically whenever `datac.save()` is called.
--8<-- "docs/usage/scripts/01_livefeed_live.py:df"
```

To retrieve saved data, first pass in the unique identifier (timestamp in this case) to the service constructor.

Then, instead of calling `.data.add_api_response()`, use `.add_parquet()`.
To retrieve saved data, first pass in the unique identifier (timestamp in this case) to the `.load()`.

## Notes

Expand Down
66 changes: 37 additions & 29 deletions docs/usage/scripts/12_livefeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,46 @@

async def my_feed() -> None:
async with FR24() as fr24:
lf = fr24.livefeed()
response = await lf.api._fetch()
response = await fr24.livefeed.fetch()
print(response)
lf.data._add_api_response(response)
print(lf.data.df)
lf.data._save_parquet()
datac = response.to_arrow()
print(datac.df)
datac.save()

await my_feed()
# --8<-- [end:script]
# %%
# --8<-- [start:response]
[
{
"timestamp": 1711911905,
"flightid": 882151247,
"latitude": -12.432657241821289,
"longitude": -172.14825439453125,
"heading": 203,
"altitude": 34000,
"ground_speed": 515,
"vertical_speed": 0,
"on_ground": False,
"callsign": "QFA7552",
"source": 0,
"registration": "N409MC",
"origin": "HNL",
"destination": "AKL",
"typecode": "B744",
"eta": 0,
}
# ... 15109 more items
]
LiveFeedAPIResp(
ctx={
"timestamp": 1711911907,
"source": "live",
"duration": None,
"hfreq": None,
"base_dir": PosixPath("/home/user/.cache/fr24"),
},
data=[
{
"timestamp": 1711911905,
"flightid": 882151247,
"latitude": -12.432657241821289,
"longitude": -172.14825439453125,
"heading": 203,
"altitude": 34000,
"ground_speed": 515,
"vertical_speed": 0,
"on_ground": False,
"callsign": "QFA7552",
"source": 0,
"registration": "N409MC",
"origin": "HNL",
"destination": "AKL",
"typecode": "B744",
"eta": 0,
}
# ... 15109 more items
],
)
# --8<-- [end:response]
#%%
"""
Expand Down Expand Up @@ -65,9 +73,9 @@ async def my_feed() -> None:

async def my_feed() -> None:
async with FR24() as fr24:
lf = fr24.livefeed(int(time.time() - 86400 * 3)) # (1)!
lf.data._add_api_response(await lf.api._fetch())
print(lf.data.df)
response = await fr24.livefeed.fetch(int(time.time() - 86400 * 3)) # (1)!
datac = response.to_arrow()
print(datac.df)

await my_feed()
# --8<-- [end:script2]
Expand Down
42 changes: 37 additions & 5 deletions src/fr24/authentication.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from __future__ import annotations

import base64
import configparser
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Literal

Expand Down Expand Up @@ -64,7 +68,7 @@ async def login(
if (u := creds.get("username")) and (p := creds.get("password")):
return await login_with_username_password(client, u, p) # type: ignore[arg-type]
if s := creds.get("subscriptionKey"):
t = creds.get("token") # optional
t = creds.get("token")
return await login_with_token_subscription_key(client, s, t) # type: ignore[arg-type]

logger.warning(
Expand Down Expand Up @@ -97,15 +101,43 @@ async def login_with_username_password(
async def login_with_token_subscription_key(
_client: httpx.AsyncClient,
subscription_key: str,
token: str,
) -> Authentication:
token: str | None,
) -> Authentication | None:
"""
Fake login with token and subscription key.
Login with subscription key and/or token.
Falls back to anonymous access if token is expired or invalid.
"""
if token is None:
return {
"userData": {
"subscriptionKey": subscription_key,
},
"message": "using environment `subscription_key`",
}

try:
payload = json.loads(base64.b64decode(token.split(".")[1]))
except Exception as e:
logger.error(
f"Failed to parse token: {e}. Falling back to anonymous access"
)
return None

if time.time() > (exp := payload["exp"]):
exp_f = datetime.fromtimestamp(exp, timezone.utc).isoformat()
logger.error(
f"Token has expired at {exp_f}. Falling back to anonymous access"
)
return None

return {
"user": {
"id": payload.get("userId"),
},
"userData": {
"subscriptionKey": subscription_key,
"accessToken": token,
"dateExpires": exp,
},
"message": "using subscriptionKey and/or accessToken.",
"message": "using environment `subscription_key` and `access_token`",
}
Loading

0 comments on commit 3868152

Please sign in to comment.