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

Better logs #658

Merged
merged 21 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0f5846b
feat(logs): add new stacktrace obtension methods
Gabriel29306 Jan 19, 2025
0b68eae
feat(logs): use new method
Gabriel29306 Jan 19, 2025
81c39a7
feat(logs): remove old method
Gabriel29306 Jan 19, 2025
465a0c7
feat(logs): make `from` arg facultative
Gabriel29306 Jan 19, 2025
b2255a0
lint
Gabriel29306 Jan 19, 2025
a203770
fix: `String((new Error()).stack!)` to `"get_addons_list"`
Gabriel29306 Jan 25, 2025
f2fccfb
fix: `[switchTo]` => `switchTo`
Gabriel29306 Jan 25, 2025
be44909
feat(logger): make log type the same length: `5`
Gabriel29306 Jan 25, 2025
fd50a98
feat(logger): better detection
Gabriel29306 Jan 25, 2025
eecf9db
Merge remote-tracking branch 'origin' into better-logs
Gabriel29306 Jan 25, 2025
60ed10f
Merge remote-tracking branch 'origin' into better-logs
Gabriel29306 Jan 25, 2025
c31a89e
lint
Gabriel29306 Jan 25, 2025
4d2df5e
chore: package lock file
Gabriel29306 Jan 26, 2025
106b6d8
fix: don't import anything from `react-native-share`
Gabriel29306 Jan 26, 2025
0f8bd12
feat(logs): better logs reading
Gabriel29306 Jan 26, 2025
c7e94f1
fix(logs): now, we need to use `startsWith` for `updateClasses` due t…
Gabriel29306 Jan 26, 2025
5db4278
Merge remote-tracking branch 'origin/main' into better-logs
Gabriel29306 Jan 26, 2025
ce66c1c
Merge branch 'main' into better-logs
Gabriel29306 Jan 29, 2025
933f1eb
Merge branch 'main' of https://github.com/PapillonApp/Papillon into b…
Gabriel29306 Feb 6, 2025
8393d34
Update GradeReaction.tsx
tryon-dev Feb 8, 2025
295ddc8
Merge branch 'main' into better-logs
tryon-dev Feb 8, 2025
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
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 35 additions & 35 deletions src/addons/addons.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as FileSystem from "expo-file-system";
import {error, log } from "@/utils/logger/logger";
import {AddonDomain, AddonManifest, AddonPermission, AddonPlacement, AddonPlacementManifest} from "@/addons/types";
import { error, log } from "@/utils/logger/logger";
import { AddonDomain, AddonManifest, AddonPermission, AddonPlacement, AddonPlacementManifest } from "@/addons/types";

async function init_addons_folder () {
if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory + "addons")).exists) {
await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + "addons");
log("Addons folder initialized at " + FileSystem.documentDirectory + "addons", String((new Error()).stack!));
log("Addons folder initialized at " + FileSystem.documentDirectory + "addons", "get_addons_list");
}
}

Expand All @@ -27,88 +27,88 @@ function generate_addons_error (error: string, name: string): AddonManifest {
async function get_addons_list (): Promise<AddonManifest[]> {
init_addons_folder();

log("Reading addons folder", String((new Error()).stack!));
log("Reading addons folder", "get_addons_list");
let res: AddonManifest[] = [];
let addons = await FileSystem.readDirectoryAsync(FileSystem.documentDirectory + "addons");
log(`Found ${addons.length} folder to check...`, String((new Error()).stack!));
log(`Found ${addons.length} folder to check...`, "get_addons_list");
for (let addon of addons) {
log(`| Starting check for folder ${addon}...`, String((new Error()).stack!));
log(`| Starting check for folder ${addon}...`, "get_addons_list");
// Check if the addon is a directory
let stat = await FileSystem.getInfoAsync(FileSystem.documentDirectory + "addons/" + addon);
if (!stat.isDirectory) {
error("| Not a directory ! Skipping...", String((new Error()).stack!));
error("| Not a directory ! Skipping...", "get_addons_list");
continue;
}

// Check if the addon has a manifest
log("| Searching for manifest.json...", String((new Error()).stack!));
log("| Searching for manifest.json...", "get_addons_list");
let info = await FileSystem.getInfoAsync(FileSystem.documentDirectory + "addons/" + addon + "/manifest.json");
if (!info.exists) {
log("| manifest.json not found ! Skipping...", String((new Error()).stack!));
log("| manifest.json not found ! Skipping...", "get_addons_list");
continue;
}


// Read the manifest
log("| Reading manifest.json...", String((new Error()).stack!));
log("| Reading manifest.json...", "get_addons_list");
let file = await FileSystem.readAsStringAsync(FileSystem.documentDirectory + "addons/" + addon + "/manifest.json");
try {
log("| Parsing manifest.json...", String((new Error()).stack!));
log("| Parsing manifest.json...", "get_addons_list");
let manifest: Partial<AddonManifest> = JSON.parse(file);

// Check if the manifest has all the required fields
log("| Loading addons...", String((new Error()).stack!));
log("| Loading addons...", "get_addons_list");
if (!manifest.name && typeof manifest.name !== "string") {
error(`| Missing properties "name" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "name" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"name\"", addon));
continue;
}
if (!manifest.author && typeof manifest.author !== "string") {
error(`| Missing properties "author" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "author" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"author\"", addon));
continue;
}
if (!manifest.version && typeof manifest.version !== "string") {
error(`| Missing properties "version" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "version" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"version\"", addon));
continue;
}
if (!manifest.placement && !Array.isArray(manifest.placement)) {
error(`| Missing properties "placement" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "placement" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"placement\"", addon));
continue;
}
if (manifest.placement.length === 0) {
error(`| Empty placement in ${addon} ! You must have 1 placement ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Empty placement in ${addon} ! You must have 1 placement ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Empty placement", addon));
continue;
}
if (!manifest.placement.every((p: AddonPlacement) => typeof p.placement === "string" && typeof p.main === "string")) {
error(`| Invalid placement in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid placement in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid placement", addon));
continue;
}
if (!manifest.permissions && !Array.isArray(manifest.permissions)) {
error(`| Missing properties "permissions" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "permissions" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"permissions\"", addon));
continue;
}
if (!manifest.domains && !Array.isArray(manifest.domains)) {
error(`| Missing properties "domains" in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Missing properties "domains" in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Missing properties \"domains\"", addon));
continue;
}

// if icon is defined, check if it's a string and if it exists
if (manifest.icon && typeof manifest.icon !== "string") {
error(`| Invalid icon in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid icon in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid icon", addon));
continue;
}
if (manifest.icon) {
let icon = await FileSystem.getInfoAsync(FileSystem.documentDirectory + "addons/" + addon + "/" + manifest.icon);
if (!icon.exists) {
error(`| Icon not found for ${addon} ! Are you sure there is a file at ${addon + "/" + manifest.icon } ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Icon not found for ${addon} ! Are you sure there is a file at ${addon + "/" + manifest.icon } ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Icon not found", addon));
continue;
}
Expand All @@ -117,20 +117,20 @@ async function get_addons_list (): Promise<AddonManifest[]> {

// check if screenshot is an array of strings and if they exists
if (manifest.screenshot && !Array.isArray(manifest.screenshot)) {
error(`| Invalid screenshot in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid screenshot in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid screenshot", addon));
continue;
}
if (manifest.screenshot) {
for (let i = 0; i < manifest.screenshot.length; i++) {
if (typeof manifest.screenshot[i] !== "string") {
error(`| Invalid screenshot in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid screenshot in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid screenshot", addon));
continue;
}
let screen = await FileSystem.getInfoAsync(FileSystem.documentDirectory + "addons/" + addon + "/" + manifest.screenshot[i]);
if (!screen.exists) {
error(`| Screenshot not found for ${addon} ! Are you sure there is a file at ${addon + "/" + manifest.screenshot[i] } ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Screenshot not found for ${addon} ! Are you sure there is a file at ${addon + "/" + manifest.screenshot[i] } ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Screenshot not found", addon));
continue;
}
Expand All @@ -140,32 +140,32 @@ async function get_addons_list (): Promise<AddonManifest[]> {

// check if development is a boolean
if (manifest.development && typeof manifest.development !== "boolean") {
error(`| Invalid development in ${addon} ! Must be true or false ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid development in ${addon} ! Must be true or false ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid development", addon));
continue;
}
// check if minAppVersion is a string
if (manifest.minAppVersion && typeof manifest.minAppVersion !== "string") {
error(`| Invalid minAppVersion in ${addon} ! Must be a string ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid minAppVersion in ${addon} ! Must be a string ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid minAppVersion", addon));
continue;
}
// check if license is a string
if (manifest.license && typeof manifest.license !== "string") {
error(`| Invalid license in ${addon} ! Must be a string ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid license in ${addon} ! Must be a string ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid license", addon));
continue;
}
// check if description is a string
if (manifest.description && typeof manifest.description !== "string") {
error(`| Invalid description in ${addon} ! Must be a string ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid description in ${addon} ! Must be a string ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid description", addon));
continue;
}

// check if placement is an array of AddonPlacement
if (!manifest.placement.every((p: AddonPlacement) => typeof p.placement === "string" && typeof p.main === "string")) {
error(`| Invalid placement in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid placement in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid placement", addon));
continue;
}
Expand All @@ -176,23 +176,23 @@ async function get_addons_list (): Promise<AddonManifest[]> {

// check if permissions is an array of AddonPermission
if (!manifest.permissions.every((p: AddonPermission) => typeof p.name === "string" && typeof p.reason === "string")) {
error(`| Invalid permissions in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid permissions in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid permissions", addon));
continue;
}

// check if domains is an array of AddonDomain
if (!manifest.domains.every((d: AddonDomain) => typeof d.domain === "string" && typeof d.reason === "string")) {
error(`| Invalid domains in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid domains in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid domains", addon));
continue;
}

// add the addon to the list
log(`| ${addon} is a valid addon !`, String((new Error()).stack!));
log(`| ${addon} is a valid addon !`, "get_addons_list");
res.push(manifest as AddonManifest);
} catch (e) {
error(`| Invalid JSON in ${addon} ! Plugin can't load, skipping...`, String((new Error()).stack!));
error(`| Invalid JSON in ${addon} ! Plugin can't load, skipping...`, "get_addons_list");
res.push(generate_addons_error("Invalid JSON", addon));
}
}
Expand Down Expand Up @@ -220,4 +220,4 @@ async function get_settings_widgets (): Promise<AddonPlacementManifest[]> {
return res;
}

export { init_addons_folder, get_addons_list, get_home_widgets, get_settings_widgets };
export { init_addons_folder, get_addons_list, get_home_widgets, get_settings_widgets };
10 changes: 5 additions & 5 deletions src/stores/account/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ export const useCurrentAccount = create<CurrentAccountStore>()((set, get) => ({

// Account is currently not authenticated,
if (typeof account.instance === "undefined") {
log("instance undefined, reloading...", "[switchTo]");
log("instance undefined, reloading...", "switchTo");
// Automatically reconnect the main instance.
const { instance, authentication } = await reload(account);
get().mutateProperty("authentication", authentication);
get().mutateProperty("instance", instance);
log("instance reload done !", "[switchTo]");
log("instance reload done !", "switchTo");
}

const accounts = useAccounts.getState().accounts;
Expand All @@ -102,13 +102,13 @@ export const useCurrentAccount = create<CurrentAccountStore>()((set, get) => ({
const { instance, authentication } = await reload(linkedAccount);
linkedAccount.instance = instance;
linkedAccount.authentication = authentication;
log("reloaded external", "[switchTo]");
log("reloaded external", "switchTo");
}

log("reloaded all external accounts", "[switchTo]");
log("reloaded all external accounts", "switchTo");

set({ linkedAccounts });
log(`done reading ${account.name} and rehydrating stores.`, "[switchTo]");
log(`done reading ${account.name} and rehydrating stores.`, "switchTo");
},

linkExistingExternalAccount: (account) => {
Expand Down
58 changes: 31 additions & 27 deletions src/utils/logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,29 @@ export function get_iso_date () {
function get_message (type: number, date: string, from: string, message: string): string
{
return (format
.replaceAll("%TYPE%", type_list[type])
.replaceAll("%TYPE%", type_list[type].padEnd(5))
.replaceAll("%DATE%", date)
.replaceAll("%FROM%", from)
.replaceAll("%MESSAGE%", message)
);
}

function get_file_from_stacktrace (stack: string): string
{
let res = "";
try {
res = stack
.split("\n")[1]
.split(/\/\/localhost:\d\d\d\d\//g)[1]
.split("//&")[0];
} catch (e) {
res = "UNKOWN";
}
return (res);

function obtain_function_name (from?: string): string {
const error = new Error(); // On génère une erreur pour obtenir la stacktrace
const stack = error.stack?.split("\n") || [];

const relevantLine = stack
.slice(3) // Ignore les premières lignes (celle du logger)
.find((line) => line.includes("at ") && line.includes("http")) // Recherche une ligne pertinente
?.trim();

// Extraire le nom de la fonction ou utiliser `from` si on trouve pas
let functionName = (relevantLine && RegExp(/at (\S+)\s\(/).exec(relevantLine)?.[1]) ?? from;
// `anon` cherche à matcher avec `anonymous` et `?anon_0_` qui sont des fonctions anonymes
if (functionName?.includes("anon_0_") || functionName?.includes("anonymous")) functionName = "";

return functionName || (from ?? "UNKOWN");
}

function save_logs_to_memory (log: string) {
Expand Down Expand Up @@ -65,26 +69,26 @@ function save_logs_to_memory (log: string) {
});
}

function log (message: string, from: string): void {
let log = get_message(0, get_iso_date(), get_file_from_stacktrace(from), message);
function log (message: string, from?: string): void {
let log = get_message(0, get_iso_date(), obtain_function_name(from), message);
save_logs_to_memory(log);
console.log(log);
}

function error (message: string, from: string): void {
let log = get_message(1, get_iso_date(), get_file_from_stacktrace(from), message);
function error (message: string, from?: string): void {
let log = get_message(1, get_iso_date(), obtain_function_name(from), message);
save_logs_to_memory(log);
console.log(log);
}

function warn (message: string, from: string): void {
let log = get_message(2, get_iso_date(), get_file_from_stacktrace(from), message);
function warn (message: string, from?: string): void {
let log = get_message(2, get_iso_date(), obtain_function_name(from), message);
save_logs_to_memory(log);
console.log(log);
}

function info (message: string, from: string): void {
let log = get_message(3, get_iso_date(), get_file_from_stacktrace(from), message);
function info (message: string, from?: string): void {
let log = get_message(3, get_iso_date(), obtain_function_name(from), message);
save_logs_to_memory(log);
console.log(log);
}
Expand Down Expand Up @@ -118,12 +122,12 @@ async function get_logs (): Promise<Log[]> {
if (res) value = JSON.parse(res);

value.forEach((item) => {
let arr = item.split("]");
const matchs = /\[([A-Z\s]+)\]\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+Z)]\[(\S+)\] (.+)/gm.exec(item);
returned.push({
type: arr[0].replace("[", ""),
date: arr[1].replace("[", ""),
from: arr[2].replace("[", ""),
message: arr[3].trim()
type: matchs?.[1]! ?? "Unkown type", // The index 0 is used for the global match
date: matchs?.[2]! ?? "Unkown date",
from: matchs?.[3]! ?? "Unkown from",
message: matchs?.[4]! ?? "Unkown content"
});
});

Expand All @@ -134,4 +138,4 @@ const delete_logs = async () => {
await AsyncStorage.removeItem("logs");
};

export { log, error, warn, info, navigate, get_logs, get_brute_logs, delete_logs };
export { log, error, warn, info, navigate, get_logs, get_brute_logs, delete_logs };
Loading
Loading