Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Chartfox support #8519

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
16 changes: 16 additions & 0 deletions fbw-a32nx/src/localization/flypad/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,22 @@
"ScanTheQrCodeOrOpen": "Scan the QR Code or Open",
"Title": "Navigraph"
},
"ChartFox": {
"AirportDoesNotExist": "Airport Does Not Exist",
"GoToThirdPartyOptions": {
"Title": "Go to 3rd Party Options to link ChartFox account",
"Button": "3rd Party Options"
},
"AuthenticateWithChartFox": "Authenticate with ChartFox",
"InsufficientEnv": "Insufficient .env File",
"IntoYourBrowserAndEnterTheCodeBelow": "into your browser and enter the code below\n",
"LoadingMsg": "Loading",
"NoAirportSelected": "No Airport Selected",
"ResetChartFoxAuthentication": "Reset ChartFox Authentication",
"ScanTheQrCodeOrOpen": "Scan the QR Code or Open",
"Title": "ChartFox"
},
"PdfUnsupported": "PDF charts are currently not supported",
"PinnedCharts": {
"Delete": "Delete",
"Edit": "Edit",
Expand Down
300 changes: 223 additions & 77 deletions fbw-a32nx/src/systems/instruments/src/EFB/Apis/ChartFox/ChartFox.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,242 @@
import React, { useContext } from 'react';
import { ChartFileType } from 'instruments/src/EFB/Store/features/navigationPage';
import { sampleData } from './Samples';

export const ChartFoxContext = React.createContext<ChartFoxClient>(undefined!);

export const useChartFox = () => useContext(ChartFoxContext);

export type ChartFoxChart = {
id: string,
parentId: string | null,
name: string,
type: string,
runway: null | string,
type: number,
typeKey: string,
url: string,
sourceUrl: string,
sourceUrlType: ChartFileType,
georefs: ChartFoxGeoRef[],
hasGeoreferences: boolean,
updatedAt: string,
runways: string[],
}

export type ChartFoxGeoRef = {
tx: number,
ty: number,
k: number,
transformAngle: number,
pdfPageRotation: number,
page: number,
}

export type ChartFoxGroupedChart = {
id: string,
name: string,
type: number,
typeKey: string,
runways: string[],
}

export type ChartFoxAirportCharts = {
arrival: ChartFoxChart[],
approach: ChartFoxChart[],
airport: ChartFoxChart[],
departure: ChartFoxChart[],
reference: ChartFoxChart[],
arrival: ChartFoxGroupedChart[],
approach: ChartFoxGroupedChart[],
airport: ChartFoxGroupedChart[],
departure: ChartFoxGroupedChart[],
reference: ChartFoxGroupedChart[],
}

export type ChartFoxAirportIndex = {
id: number,
ident: string,
icaoCode: string,
iataCode: string,
name: string,
type: string,
latitude: number,
longitude: number,
elevationFt: number,
isoA2Country: string,
hasCharts: boolean,
hasSources: boolean,
groupedCharts: ChartFoxAirportCharts,
}

export const emptyChartFoxCharts = {
arrival: [] as ChartFoxGroupedChart[],
approach: [] as ChartFoxGroupedChart[],
airport: [] as ChartFoxGroupedChart[],
departure: [] as ChartFoxGroupedChart[],
reference: [] as ChartFoxGroupedChart[],
};

const emptyAirportIndex: ChartFoxAirportIndex = {
id: 0,
ident: '',
icaoCode: '',
iataCode: '',
name: '',
type: '',
latitude: 0,
longitude: 0,
elevationFt: 0,
isoA2Country: '',
hasCharts: false,
hasSources: false,
groupedCharts: emptyChartFoxCharts,
};

export const UseChartFoxSamples = true;

export class ChartFoxClient {
private static token = process.env.CHARTFOX_SECRET;
private static token = '';

public static sufficientEnv() {
return !!ChartFoxClient.token;
// return !!ChartFoxClient.token;
return true;
}

public async getChartList(icao: string): Promise<ChartFoxAirportCharts> {
if (ChartFoxClient.sufficientEnv()) {
if (icao.length === 4) {
try {
const chartJsonResp = await fetch(`https://chartfox.org/api/charts/grouped/${icao}?token=${ChartFoxClient.token}`, { method: 'POST' });

if (chartJsonResp.ok) {
const chartJson = await chartJsonResp.json();

const groundLayoutArray: ChartFoxChart[] = chartJson.charts['2'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

const generalArray: ChartFoxChart[] = chartJson.charts['0'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

const textualArray: ChartFoxChart[] = chartJson.charts['1'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

const sidArray: ChartFoxChart[] = chartJson.charts['6'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

const starArray: ChartFoxChart[] = chartJson.charts['7'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

const approachArray: ChartFoxChart[] = chartJson.charts['8'].charts.map((charts) => ({
name: charts.name,
type: charts.type,
runway: charts.runway,
url: charts.url,
}));

return {
arrival: starArray,
approach: approachArray,
airport: groundLayoutArray,
departure: sidArray,
reference: generalArray.concat(textualArray),
};
}
} catch (_) {
console.log('Token Authentication Failed. #CF101');
public async getChart(id: string): Promise<ChartFoxChart> {
if (!ChartFoxClient.sufficientEnv() || id === '') {
return null;
}

try {
let jsonValue;
if (UseChartFoxSamples) {
jsonValue = sampleData[id];
} else {
const jsonResp = await fetch(`https://api.chartfox.org/v2/charts/${id}`, {
headers: {
'content-type': 'application/json',
'authorization': `Bearer ${ChartFoxClient.token}`,
},
});

if (!jsonResp.ok) {
return null;
}

jsonValue = await jsonResp.json();
}
return {
id: jsonValue.id,
parentId: jsonValue.parent_id,
name: jsonValue.name,
type: jsonValue.type,
typeKey: jsonValue.type_key,
url: jsonValue.url,
sourceUrl: jsonValue.source_url,
sourceUrlType: jsonValue.source_url_type,
georefs: jsonValue.georefs.map((georef) => ({
tx: georef.tx,
ty: georef.ty,
k: georef.k,
transformAngle: georef.transform_angle,
pdfPageRotation: georef.pdf_page_rotation,
page: georef.page,
})),
hasGeoreferences: jsonValue.has_georeferences,
updatedAt: jsonValue.updated_at,
runways: jsonValue.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
};
} catch (e) {
console.log(`Error getting ChartFox chart: ${e}`);
}

return null;
}

public async getChartIndex(icao: string): Promise<ChartFoxAirportIndex> {
if (!ChartFoxClient.sufficientEnv() || icao.length !== 4) {
return emptyAirportIndex;
}

try {
let chartJson;
if (UseChartFoxSamples) {
chartJson = sampleData[icao];
} else {
const chartJsonResp = await fetch(`https://chartfox.org/${icao}`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'authorization': `Bearer ${ChartFoxClient.token}`,
},
});

if (!chartJsonResp.ok) {
return emptyAirportIndex;
}

chartJson = await chartJsonResp.json();
}
const groundLayoutArray: ChartFoxGroupedChart[] = chartJson.props.groupedCharts['3'].map((chart) => ({
id: chart.id,
name: chart.name,
type: chart.type,
typeKey: chart.type_key,
runways: chart.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
}));

const unknownArray: ChartFoxGroupedChart[] = chartJson.props.groupedCharts['0'].map((chart) => ({
id: chart.id,
name: chart.name,
type: chart.type,
typeKey: chart.type_key,
runways: chart.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
}));

const sidArray: ChartFoxGroupedChart[] = chartJson.props.groupedCharts['4'].map((chart) => ({
id: chart.id,
name: chart.name,
type: chart.type,
typeKey: chart.type_key,
runways: chart.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
}));

const starArray: ChartFoxGroupedChart[] = chartJson.props.groupedCharts['5'].map((chart) => ({
id: chart.id,
name: chart.name,
type: chart.type,
typeKey: chart.type_key,
runways: chart.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
}));

const approachArray: ChartFoxGroupedChart[] = chartJson.props.groupedCharts['6'].map((chart) => ({
id: chart.id,
name: chart.name,
type: chart.type,
typeKey: chart.type_key,
runways: chart.meta.find((meta) => meta.type_key === 'Runways')?.value ?? [],
}));

return {
id: chartJson.props.airport.id,
ident: chartJson.props.airport.ident,
icaoCode: chartJson.props.airport.icao_code,
iataCode: chartJson.props.airport.iata_code,
name: chartJson.props.airport.name,
type: chartJson.props.airport.type,
latitude: chartJson.props.airport.latitude,
longitude: chartJson.props.airport.longitude,
elevationFt: chartJson.props.airport.elevation_ft,
isoA2Country: chartJson.props.airport.iso_a2_country,
hasCharts: chartJson.props.airport.has_charts,
hasSources: chartJson.props.airport.has_sources,
groupedCharts: {
arrival: starArray,
approach: approachArray,
airport: groundLayoutArray,
departure: sidArray,
reference: unknownArray,
},
};
} catch (e) {
// console.log('Token Authentication Failed. #CF101');
console.log(e);
}

return {
arrival: [],
approach: [],
airport: [],
departure: [],
reference: [],
};
return emptyAirportIndex;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const sampleData = {};
Loading