commit 4a7487380bcd7147e41304503cf08e269e964265 parent 1d4599dae3a9ef4b185e992e99ce7eb1072d3fc7 Author: triesap <137732411+triesap@users.noreply.github.com> Date: Thu, 10 Apr 2025 22:12:33 +0000 Edit `core` keystore utils and `tangle` keys nostr commands. Edit `/init` refactor client logic, fix use existing nostr key configuration option, fix error messages. Add library config, stores. Add/edit routes, styles, utils. Diffstat:
125 files changed, 1211 insertions(+), 1116 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -45,9 +45,9 @@ justfile setup.py target -/crates/tauri/gen -/crates/tauri/tauri*.conf.json -/crates/tauri/conf -/crates/tauri/Entitlements*.plist -!/crates/tauri/tauri.conf.json +/crates/tangle/gen +/crates/tangle/tauri*.conf.json +/crates/tangle/conf +/crates/tangle/Entitlements*.plist +!/crates/tangle/tauri.conf.json app*.png \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock @@ -3825,27 +3825,6 @@ dependencies = [ ] [[package]] -name = "radroots" -version = "0.0.1" -dependencies = [ - "radroots_core", - "radroots_model", - "serde", - "serde_json", - "sqlx", - "tauri", - "tauri-build", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-geolocation", - "tauri-plugin-http", - "tauri-plugin-notification", - "tauri-plugin-os", - "tauri-plugin-shell", - "tauri-plugin-store", -] - -[[package]] name = "radroots_core" version = "0.0.1" dependencies = [ @@ -5012,6 +4991,27 @@ dependencies = [ ] [[package]] +name = "tangle" +version = "0.0.1" +dependencies = [ + "radroots_core", + "radroots_model", + "serde", + "serde_json", + "sqlx", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-fs", + "tauri-plugin-geolocation", + "tauri-plugin-http", + "tauri-plugin-notification", + "tauri-plugin-os", + "tauri-plugin-shell", + "tauri-plugin-store", +] + +[[package]] name = "tao" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -3,5 +3,5 @@ resolver = "2" members = [ "crates/core", "crates/model", - "crates/tauri", + "crates/tangle", ] diff --git a/app/src/lib/config.ts b/app/src/lib/config.ts @@ -0,0 +1,3 @@ +export const _cfg = { + role_default: `public` +} as const; diff --git a/app/src/lib/store.ts b/app/src/lib/store.ts @@ -0,0 +1,4 @@ +import { writable } from "svelte/store"; + +export const cfg_role = writable<string>(); +export const cfg_setup = writable<boolean | undefined>(undefined); diff --git a/app/src/lib/util/index.ts b/app/src/lib/util/index.ts @@ -4,9 +4,9 @@ import { PUBLIC_RADROOTS_URL } from "$env/static/public"; import { ls } from "$lib/locale/i18n"; import { TauriClientDatabase, TauriClientDatastore, TauriClientFs, TauriClientGeolocation, TauriClientGui, TauriClientHttp, TauriClientKeys, TauriClientRadroots } from "@radroots/client"; import { Geocoder } from "@radroots/geocoder"; -import { app_notify, get_store, handle_err, NostrSyncService } from "@radroots/lib-app"; +import { app_notify, get_store, handle_err, NostrSyncService, type NavigationRouteParamKey, type NavigationRouteParamTuple } from "@radroots/lib-app"; import { NostrEventService, NostrKeyService } from "@radroots/nostr-util"; -import { encode_route, type CallbackPromise, type NavigationParamTuple } from "@radroots/util"; +import { encode_route, type CallbackPromise } from "@radroots/util"; import type { NavigationRoute } from "./routes"; export const db = new TauriClientDatabase(); @@ -24,9 +24,9 @@ export const nostre = new NostrEventService(); export let nostrsync: NostrSyncService if (browser) nostrsync = new NostrSyncService(); -export const route = async (nav_route: NavigationRoute, params: NavigationParamTuple[] = []): Promise<void> => { +export const route = async (nav_route: NavigationRoute, params: NavigationRouteParamTuple[] = []): Promise<void> => { try { - if (params.length) await goto(encode_route<NavigationRoute>(nav_route, params)); + if (params.length) await goto(encode_route<NavigationRoute, NavigationRouteParamKey>(nav_route, params)); else await goto(nav_route); } catch (e) { await handle_err(e, `route`); diff --git a/app/src/lib/util/nostr/sync.ts b/app/src/lib/util/nostr/sync.ts @@ -1,21 +1,50 @@ -import { get_store, handle_err, ndk_user } from "@radroots/lib-app"; +import { ls } from "$lib/locale/i18n"; +import { get_store, handle_err, ndk_user, nostr_sync_prevent } from "@radroots/lib-app"; import { throw_err } from "@radroots/util"; -import { db, nostrsync } from ".."; +import { db, gui, nostrsync } from ".."; +import { err } from "../err"; -export const nostr_sync_metadata = async (): Promise<void> => { +export const nostr_sync = async (): Promise<void> => { try { + const $ls = get_store(ls); const $ndk_user = get_store(ndk_user); - const tb_nostr_profile = await db.nostr_profile_read({ - public_key: $ndk_user?.pubkey, - }); - if (`err` in tb_nostr_profile) throw_err(tb_nostr_profile.err); - const ev_metadata = await nostrsync.metadata({ - metadata: tb_nostr_profile.result, - }); - if (`err` in ev_metadata) throw_err(ev_metadata.err); - await ev_metadata.publish(); + if (!$ndk_user.pubkey) return void await gui.alert( + `${$ls(`error.client.nostr_sync_failure`)}` + ); + const $nostr_sync_prevent = get_store(nostr_sync_prevent); + if ($nostr_sync_prevent) { + const confirm = await gui.confirm({ + message: `${$ls(`error.client.nostr_sync_disabled`)}`, + }); + if (confirm) { + nostr_sync_prevent.set(false); + await nostr_sync(); + } + return; + } + console.log(`[nostr_sync] start`); + const nostr_relays = await db.nostr_relay_read_list({ + table: [`on_profile`, { public_key: $ndk_user.pubkey }] + }); //@todo + + if (`err` in nostr_relays) return throw_err(nostr_relays); + if (!nostr_relays.results.length) return throw_err(err.nostr.no_relays); + await nostr_sync_metadata(); + console.log(`[nostr_sync] done`); } catch (e) { - await handle_err(e, `nostr_sync_metadata`); - //location.reload(); @todo + await handle_err(e, `nostr_sync`); } -}; -\ No newline at end of file +}; + +export const nostr_sync_metadata = async (): Promise<void> => { + const $ndk_user = get_store(ndk_user); + const { pubkey: public_key } = $ndk_user; + if (!public_key) throw_err(`todo-public-key-undefined`); + const tb_nostr_profile = await db.nostr_profile_read({ public_key }); + if (`err` in tb_nostr_profile) throw_err(tb_nostr_profile); + const ev = await nostrsync.metadata({ metadata: tb_nostr_profile.result }); + if (`err` in ev) throw_err(ev); + await ev.publish(); +}; + + diff --git a/app/src/routes/(app)/+layout.svelte b/app/src/routes/(app)/+layout.svelte @@ -8,10 +8,13 @@ ndk, ndk_user, nostr_ndk_configured, + nostr_sync_retry_handler, } from "@radroots/lib-app"; import { ndk_init } from "@radroots/nostr-util"; import { throw_err } from "@radroots/util"; + import { _cfg } from "$lib/config"; + import { cfg_role, cfg_setup } from "$lib/store"; import { nostr_sync_metadata } from "$lib/util/nostr/sync"; import { onMount } from "svelte"; import type { LayoutProps } from "./$types"; @@ -36,35 +39,46 @@ await datastore.init(); await idb_init(); await nostr_init(); + // + // initial setup + const ds_setup = await datastore.get(`is_setup`); + if (`err` in ds_setup) cfg_setup.set(false); + else cfg_setup.set(true); + // + // get role + const ds_role = await datastore.get(`role`); + if (`err` in ds_role) { + await datastore.set(`role`, _cfg.role_default); + cfg_role.set(_cfg.role_default); + } else cfg_role.set(ds_role.result); } catch (e) { await handle_err(e, `init`); } }; const nostr_init = async (): Promise<void> => { - try { - if (!data.public_key) throw_err(`*-key_nostr`); - const keys_nostr_read = await keys.nostr_read(data.public_key); - if (`err` in keys_nostr_read) throw_err(keys_nostr_read.err); - const tb_nostr_relays = await db.nostr_relay_read_list({ - table: [`on_profile`, { public_key: data.public_key }], - }); - if (`err` in tb_nostr_relays) throw_err(tb_nostr_relays.err); - for (const { url } of tb_nostr_relays.results) - $ndk.addExplicitRelay(url); - await $ndk.connect(); - const ndk_user_init = await ndk_init({ - $ndk, - secret_key: keys_nostr_read.secret_key, - }); - nostr_ndk_configured.set(!!ndk_user_init); - if (!ndk_user_init) throw_err(`error.nostr.ndk_user_undefined`); - $ndk_user = ndk_user_init; - $ndk_user.ndk = $ndk; - await nostr_sync_metadata(); - } catch (e) { - await handle_err(e, `nostr_init`); - } + if (!data.public_key) throw_err(`*-key_nostr`); + const keys_nostr_read = await keys.nostr_read(data.public_key); + if (`err` in keys_nostr_read) throw_err(keys_nostr_read); + const tb_nostr_relays = await db.nostr_relay_read_list({ + table: [`on_profile`, { public_key: data.public_key }], + }); + if (`err` in tb_nostr_relays) throw_err(tb_nostr_relays); + $ndk.explicitRelayUrls = []; + for (const { url } of tb_nostr_relays.results) + $ndk.addExplicitRelay(url); + await $ndk.connect().then(() => { + console.log(`[tangle] ndk connected`); + }); + const ndk_user_init = await ndk_init({ + $ndk, + secret_key: keys_nostr_read.secret_key, + }); + nostr_ndk_configured.set(!!ndk_user_init); + if (!ndk_user_init) throw_err(`error.nostr.ndk_user_undefined`); + $ndk_user = ndk_user_init; + $ndk_user.ndk = $ndk; + await nostr_sync_retry_handler(nostr_sync_metadata); }; app_notify.subscribe(async (_app_notify) => { @@ -73,6 +87,31 @@ await gui.notify_send($app_notify); app_notify.set(``); }); + + cfg_role.subscribe(async (_cfg_role) => { + if (!_cfg_role) return; + }); + + cfg_setup.subscribe(async (_cfg_setup) => { + console.log(`_cfg_setup `, _cfg_setup); + if (!_cfg_setup) return; + }); </script> -{@render children()} +{#if typeof $cfg_setup !== `undefined`} + {#if !$cfg_setup} + {@render children()} + {:else} + <div class={`flex flex-col w-full pt-20 justify-start items-center`}> + <button + class={`flex flex-row justify-center items-center`} + onclick={async () => { + await datastore.remove(`is_setup`); + location.reload(); + }} + > + {`setup device`} + </button> + </div> + {/if} +{/if} diff --git a/app/src/routes/(app)/+page.svelte b/app/src/routes/(app)/+page.svelte @@ -1,29 +1,39 @@ <script lang="ts"> import { ls } from "$lib/locale/i18n"; + import { cfg_role } from "$lib/store"; import { gui, route } from "$lib/util"; - import { handle_err, Home } from "@radroots/lib-app"; - import type { ResolveAccountInfo } from "@radroots/util"; + import { handle_err, Home, type IHomeViewData } from "@radroots/lib-app"; - let data: ResolveAccountInfo | undefined = $state(undefined); + let data: IHomeViewData | undefined = $state({}); </script> -<Home - {ls} - basis={{ - data: data, - lc_handle_farms: async () => { - try { - await route(`/`); - } catch (e) { - await handle_err(e, `lc_handle_farms`); - } - }, - lc_handle_products: async () => { - try { - await gui.alert(`@todo`); - } catch (e) { - await handle_err(e, `lc_handle_products`); - } - }, - }} -/> +{#if data} + {#if $cfg_role === `farmer`} + <div class={`flex flex-col pt-20 justify-start items-center`}> + <p class={`font-sans font-[400] text-layer-0-glyph`}> + {`farmer`} + </p> + </div> + {:else if $cfg_role === `public`} + <Home + {ls} + basis={{ + data, + lc_handle_farms: async () => { + try { + await route(`/`); + } catch (e) { + await handle_err(e, `lc_handle_farms`); + } + }, + lc_handle_products: async () => { + try { + await gui.alert(`@todo`); + } catch (e) { + await handle_err(e, `lc_handle_products`); + } + }, + }} + /> + {/if} +{/if} diff --git a/app/src/routes/(app)/profile/+page.svelte b/app/src/routes/(app)/profile/+page.svelte @@ -45,13 +45,12 @@ data, loading_photo_upload, loading_photo_upload_open, - lc_on_destroy: async ({ public_key }) => { + lc_on_destroy: async () => { try { const tb_nostrprofile = await db.nostr_profile_read({ - public_key, + public_key: $ndk_user?.pubkey, }); - if (`err` in tb_nostrprofile) - throw_err(tb_nostrprofile.err); //@todo + if (`err` in tb_nostrprofile) throw_err(tb_nostrprofile); //@todo await nostr_sync_metadata(); } catch (e) { await handle_err(e, `lc_on_destroy`); @@ -63,8 +62,7 @@ if (!photo_path || !public_key) return void (await route(`/`)); const keys_nostr_read = await keys.nostr_read(public_key); - if (`err` in keys_nostr_read) - throw_err(keys_nostr_read.err); + if (`err` in keys_nostr_read) throw_err(keys_nostr_read); if (photo_path) { const confirm = await gui.confirm({ message: is_photo_existing @@ -100,7 +98,7 @@ secret_key: keys_nostr_read.secret_key, }); if (`err` in res_fetch_media_image_upload) - throw_err(res_fetch_media_image_upload.err); + throw_err(res_fetch_media_image_upload); const { res_base: upload_res_base, res_path: upload_res_path, @@ -112,7 +110,7 @@ mime_type: upload_file_path.mime_type, }); if (`err` in tb_media_image_create) - throw_err(tb_media_image_create.err); + throw_err(tb_media_image_create); const tb_nostr_profile_update = await db.nostr_profile_update({ filter: { public_key }, @@ -121,7 +119,7 @@ }, }); if (`err` in tb_nostr_profile_update) - throw_err(tb_nostr_profile_update.err); + throw_err(tb_nostr_profile_update); await route(`/`); } catch (e) { await handle_err(e, `lc_handle_back`); diff --git a/app/src/routes/(app)/profile/edit/+page.svelte b/app/src/routes/(app)/profile/edit/+page.svelte @@ -76,7 +76,7 @@ }, }); if (`err` in nostr_profile_update) - throw_err(nostr_profile_update.err); + throw_err(nostr_profile_update); const tb_nostr_profile = await db.nostr_profile_read({ public_key, }); @@ -84,9 +84,8 @@ JSON.stringify(tb_nostr_profile, null, 4), `tb_nostr_profile`, ); - if (`err` in tb_nostr_profile) - throw_err(tb_nostr_profile.err); - nostr_sync_metadata(); // no await + if (`err` in tb_nostr_profile) throw_err(tb_nostr_profile); + nostr_sync_metadata(); // leave off await await route(`/profile`); } catch (e) { await handle_err(e, `lc_handle_back`); diff --git a/app/src/routes/(cfg)/init/+page.svelte b/app/src/routes/(cfg)/init/+page.svelte @@ -2,48 +2,27 @@ import { goto } from "$app/navigation"; import { PUBLIC_NOSTR_RELAY_DEFAULTS } from "$env/static/public"; import { ls } from "$lib/locale/i18n"; - import { - datastore, - db, - gui, - keys, - nostrkey, - radroots, - route, - } from "$lib/util"; + import { datastore, db, gui, keys, radroots, route } from "$lib/util"; import { cfg_delay } from "$lib/util/conf"; + import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { app_lo, app_loading, - app_notify, ButtonLayoutPair, carousel_dec, carousel_inc, carousel_index, carousel_index_max, - EntryLineIdb, + EntryLine, fmt_id, handle_err, - idb, - IdbLib, - Input, - LabelDisplay, LoadSymbol, LogoCircle, view_effect, } from "@radroots/lib-app"; - import { - el_id, - form_fields, - sleep, - str_capitalize_words, - type ResultPass, - } from "@radroots/util"; + import { el_id, form_fields, sleep, type ResultPass } from "@radroots/util"; import { onMount } from "svelte"; - type IdbKey = `nostr:key:add` | `nostr:profile` | `#key_nostrp`; - const kv = new IdbLib<IdbKey>(idb); - const page_carousel: Record<View, { max_index: number }> = { cfg_key: { max_index: 2, @@ -65,23 +44,25 @@ view_effect<View>(view); }); - type CfgKeyOpt = `cfg_keygen` | `cfg_keyadd`; - let cgf_keyopt: CfgKeyOpt | undefined = $state(undefined); + let loading_submit = $state(false); type CfgRole = `farmer` | `personal`; let cfg_role: CfgRole | undefined = $state(undefined); - let cfg_profile_nostr_publickey = $state(``); - const cfg_profile_nostr_publickey_npub = $derived( - cfg_profile_nostr_publickey - ? nostrkey.npub(cfg_profile_nostr_publickey) || `` - : ``, - ); + type CfgKeyOpt = `nostr_keygen` | `nostr_keyadd`; + let cgf_key_opt: CfgKeyOpt | undefined = $state(undefined); + let cfg_key_add_existing_val = $state(``); - let cfg_profile_profilename_valid = $state(false); - let cfg_profile_profilename_loading = $state(false); + let cfg_profile_nip05_opt = $state(false); + let cfg_profile_name_val = $state(``); + let cfg_profile_name_valid = $state(false); + let cfg_profile_name_loading = $state(false); - let loading_submit = $state(false); + const cfg_profile_name_skip = $derived( + view.toString() === `cfg_profile` && + $carousel_index === 0 && + !cfg_profile_nip05_opt, + ); onMount(async () => { try { @@ -92,20 +73,13 @@ }); const init = async (): Promise<void> => { - const nostrkey_all = await keys.nostr_read_all(); - if (`results` in nostrkey_all && nostrkey_all.results.length) { - console.log(`init EXISTING!`, nostrkey_all.results); - handle_view(`eula`); - } else { - handle_view(view); - } - await kv.init(); + const nostrkey_all = await keys.nostr_read_all(); //@todo + handle_view(view); }; const handle_view = (new_view: View): void => { - console.log(`new_view `, new_view); if (new_view === `cfg_key` && view === `cfg_profile`) { - const offset = cgf_keyopt === `cfg_keygen` ? 1 : 0; + const offset = cgf_key_opt === `nostr_keygen` ? 1 : 0; carousel_index.set(page_carousel[new_view].max_index - offset); } else { carousel_index.set(0); @@ -157,14 +131,15 @@ return void (await reset( `${$ls(`error.init.configuration_failure`)}`, )); - await kv.save(`#key_nostrp`, keys_nostr_create.public_key); + await datastore.set(`init_nostr`, keys_nostr_create.public_key); }; const key_add = async (secret_key: string): Promise<void> => { const keys_nostr_add = await keys.nostr_add(secret_key); + console.log(`keys_nostr_add `, keys_nostr_add); if (`err` in keys_nostr_add) return void (await gui.alert(`${$ls(`common.invalid_key`)}`)); - await kv.save(`#key_nostrp`, keys_nostr_add.public_key); + await datastore.set(`init_nostr`, keys_nostr_add.public_key); }; const configure_device = async ( @@ -174,6 +149,7 @@ const nostr_profile_add = await db.nostr_profile_create({ public_key, name: profile_name ? profile_name : undefined, + display_name: profile_name ? profile_name : undefined, }); if (`err` in nostr_profile_add || `err_s` in nostr_profile_add) return void (await gui.alert( @@ -200,9 +176,18 @@ return { pass: true }; }; + const confirm_profile_add_without_name = async (): Promise<boolean> => { + const confirm = await gui.confirm({ + message: `${$ls(`notification.init.no_profile_option`)}`, + cancel: `${$ls(`icu.add_*`, { value: `${$ls(`common.profile`)}` })}`, + ok: `${$ls(`common.continue`)}`, + }); + return confirm; + }; + const handle_choose_key_gen_or_add = async (): Promise<void> => { try { - if (cgf_keyopt === `cfg_keyadd`) + if (cgf_key_opt === `nostr_keyadd`) return void (await carousel_inc(view)); await key_gen(); handle_view(`cfg_profile`); @@ -211,83 +196,106 @@ } }; - const handle_submit_key_add = async (): Promise<void> => { + const handle_key_add_existing = async (): Promise<void> => { try { - const nostrkey_add = await kv.read(`nostr:key:add`); - if (!nostrkey_add) + if (!cfg_key_add_existing_val) return void (await gui.alert( - `${$ls(`icu.enter_a_valid_*`, { value: `${$ls(`common.key`)}` })}`, + `${$ls(`icu.enter_a_*`, { value: `${$ls(`common.nostr_key`)}`.toLowerCase() })}`, )); - const key_nostr_read = await keys.nostr_read(nostrkey_add); - if (`err` in key_nostr_read) - return void (await reset( - `${$ls(`error.init.configuration_failure`)}`, + const key_add_signer = new NDKPrivateKeySigner( + cfg_key_add_existing_val, + ); + const key_add_user = await key_add_signer.user(); + const key_add_hex_secret_key = key_add_signer.privateKey; + const key_add_hex_public_key = key_add_user.pubkey; + const key_nostr_read = await keys.nostr_read( + cfg_key_add_existing_val, + ); + if ( + (`err` in key_nostr_read && + key_nostr_read.err !== `error.keystore.key_not_found`) || + !key_add_hex_secret_key || + !key_add_hex_public_key + ) + return void (await gui.alert( + `${$ls(`icu.enter_a_valid_*`, { value: `${$ls(`common.nostr_key`)}`.toLowerCase() })}`, )); - await key_add(key_nostr_read.secret_key); - kv.del(`nostr:key:add`); + await key_add(key_add_hex_secret_key); + cfg_key_add_existing_val = ``; return void handle_view(`cfg_profile`); } catch (e) { - await handle_err(e, `handle_submit_key_add`); + await handle_err(e, `handle_key_add_existing`); + return void (await gui.alert( + `${$ls(`icu.not_a_valid_*`, { value: `${$ls(`common.nostr_key`)}`.toLowerCase() })}`, + )); } }; const handle_profile_add = async (): Promise<void> => { try { - if (cfg_profile_profilename_loading) return; - const kv_keynostrp = await kv.read(`#key_nostrp`); - if (!kv_keynostrp) + if (cfg_profile_name_loading) return; + const ds_nostr_key_init = await datastore.get(`init_nostr`); + if (`err` in ds_nostr_key_init) return void (await reset( `${$ls(`error.init.configuration_failure`)}`, )); //@todo - const key_nostr_read = await keys.nostr_read(kv_keynostrp); + const key_nostr_read = await keys.nostr_read( + ds_nostr_key_init.result, + ); if (`err` in key_nostr_read) return void (await reset( `${$ls(`error.init.configuration_failure`)}`, )); //@todo - const kv_profilename = await kv.read(`nostr:profile`); - if (!kv_profilename) - return void (await gui.alert( - `${$ls(`icu.enter_a_*`, { value: `${$ls(`common.profile_name`)}`.toLowerCase() })}`, - )); - cfg_profile_profilename_loading = true; - const profile_req = await radroots.fetch_profile_request({ - profile_name: kv_profilename, - secret_key: key_nostr_read.secret_key, - }); - if (`err` in profile_req) - return void (await gui.alert( - `${$ls(profile_req.err, { default: `${$ls(`error.client.http.request_failure`)}` })}`, - )); - const confirm = await gui.confirm({ - message: `${`${$ls(`icu.the_*_is_available`, { value: `${$ls(`common.profile_name`).toLowerCase()} "${kv_profilename}"` })}`}. ${`${$ls(`common.would_you_like_to_use_it_q`)}`}`, - cancel: `${$ls(`common.no`)}`, - ok: `${$ls(`common.yes`)}`, - }); - if (!confirm) return; - const profile_create = await radroots.fetch_profile_create({ - tok: profile_req.result, - secret_key: key_nostr_read.secret_key, - }); - if (`err` in profile_create) - return void (await gui.alert( - `${$ls(profile_create.err, { default: `${$ls(`error.client.http.request_failure`)}` })}`, - )); - await datastore.setp( - `radroots_profile`, - kv_keynostrp, - profile_create.result, - ); + if (cfg_profile_nip05_opt) { + if (!cfg_profile_name_val) + return void (await gui.alert( + `${$ls(`icu.enter_a_*`, { value: `${$ls(`common.profile_name`)}`.toLowerCase() })}`, + )); + cfg_profile_name_loading = true; + const profile_req = await radroots.fetch_profile_request({ + profile_name: cfg_profile_name_val, + secret_key: key_nostr_read.secret_key, + }); + if (`err` in profile_req) + return void (await gui.alert( + `${$ls(profile_req.err, { default: `${$ls(`error.client.http.request_failure`)}` })}`, + )); + const confirm = await gui.confirm({ + message: `${`${$ls(`icu.the_*_is_available`, { value: `${$ls(`common.profile_name`).toLowerCase()} "${cfg_profile_name_val}"` })}`}. ${`${$ls(`common.would_you_like_to_use_it_q`)}`}`, + cancel: `${$ls(`common.no`)}`, + ok: `${$ls(`common.yes`)}`, + }); + if (!confirm) return; + const profile_create = await radroots.fetch_profile_create({ + tok: profile_req.result, + secret_key: key_nostr_read.secret_key, + }); + if (`err` in profile_create) + return void (await gui.alert( + `${$ls(profile_create.err, { default: `${$ls(`error.client.http.request_failure`)}` })}`, + )); + await datastore.setp( + `radroots_profile`, + ds_nostr_key_init.result, + profile_create.result, + ); + } else if (!cfg_profile_name_val) { + const confirm = await confirm_profile_add_without_name(); + if (!confirm) + return void el_id(fmt_id(`nostr:profile`))?.focus(); + } await carousel_inc(view); } catch (e) { await handle_err(e, `handle_profile_add`); } finally { - cfg_profile_profilename_loading = false; + cfg_profile_name_loading = false; } }; const handle_set_role = async (): Promise<void> => { if (!cfg_role) cfg_role = `personal`; await datastore.set(`role`, cfg_role); + await datastore.set(`is_setup`, new Date().toISOString()); handle_view(`eula`); }; @@ -300,7 +308,7 @@ case 1: return await handle_choose_key_gen_or_add(); case 2: - return await handle_submit_key_add(); + return await handle_key_add_existing(); } case `cfg_profile`: switch ($carousel_index) { @@ -317,16 +325,28 @@ case `cfg_key`: switch ($carousel_index) { case 1: { - cgf_keyopt = undefined; + cgf_key_opt = undefined; return await carousel_dec(view); } - case 2: + case 2: { + cfg_key_add_existing_val = ``; return await carousel_dec(view); + } } case `cfg_profile`: switch ($carousel_index) { - case 0: + case 0: { + if (cfg_profile_name_skip) { + const confirm = + await confirm_profile_add_without_name(); + if (!confirm) + return void el_id( + fmt_id(`nostr:profile`), + )?.focus(); + return void carousel_inc(view); + } return handle_view(`cfg_key`); + } case 1: return carousel_dec(view); } @@ -336,19 +356,21 @@ const submit = async (): Promise<void> => { try { loading_submit = true; - const kv_keynostrp = await kv.read(`#key_nostrp`); - if (!kv_keynostrp) + const ds_nostr_key_init = await datastore.get(`init_nostr`); + if (`err` in ds_nostr_key_init) return void (await reset( `${$ls(`error.init.configuration_failure`)}`, )); //@todo - const key_nostr_read = await keys.nostr_read(kv_keynostrp); + const key_nostr_read = await keys.nostr_read( + ds_nostr_key_init.result, + ); if (`err` in key_nostr_read) return void (await reset( `${$ls(`error.init.configuration_failure`)}`, )); //@todo const radroots_profile = await datastore.getp( `radroots_profile`, - kv_keynostrp, + ds_nostr_key_init.result, ); if (`result` in radroots_profile) { await radroots.fetch_profile_activate({ @@ -357,23 +379,15 @@ }); //@todo } const configuration_result = await configure_device( - kv_keynostrp, - await kv.read(`nostr:profile`), + ds_nostr_key_init.result, + cfg_profile_name_val, ); - if (configuration_result && `pass` in configuration_result) { - const confirm = await gui.confirm({ - message: `${$ls(`notification.init.on_complete`)}`, - ok: `${$ls(`common.continue`)}`, - cancel: str_capitalize_words( - `${$ls(`common.hide_alerts`)}`, - ), - }); - if (confirm) { - await gui.notify_init(); - app_notify.set(`${$ls(`notification.init.on_first_load`)}`); - } - await route(`/`); - } + if (!configuration_result) + return void (await reset( + `${$ls(`error.init.configuration_failure`)}`, + )); //@todo + route(`/`); + await gui.notify_init(); } catch (e) { await handle_err(e, `submit`); } finally { @@ -387,24 +401,6 @@ class={`flex flex-col h-full w-full justify-start items-center`} > <div - class={`z-10 absolute max-m_0:bottom-0 bottom-10 left-0 flex flex-col w-full justify-center items-center`} - > - <ButtonLayoutPair - basis={{ - continue: { - label: `${$ls(`common.continue`)}`, - disabled: $carousel_index === 1 && !cgf_keyopt, - callback: async () => await handle_continue(), - }, - back: { - label: `${$ls(`common.back`)}`, - visible: $carousel_index > 0, - callback: async () => await handle_back(), - }, - }} - /> - </div> - <div data-carousel-container={`cfg_key`} class={`carousel-container flex h-full w-full`} > @@ -470,7 +466,7 @@ role="button" tabindex="0" onclick={async () => { - cgf_keyopt = undefined; + cgf_key_opt = undefined; }} onkeydown={null} > @@ -488,10 +484,10 @@ class={`flex flex-col w-full gap-6 justify-center items-center`} > <button - class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${cgf_keyopt === `cfg_keygen` ? `layer-1-surface-apply-active layer-1-raise-apply layer-1-ring-apply` : `bg-layer-1-surface`} el-re`} + class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${cgf_key_opt === `nostr_keygen` ? `layer-1-surface-apply-active layer-1-raise-apply layer-1-ring-apply` : `bg-layer-1-surface`} el-re`} onclick={async (ev) => { ev.stopPropagation(); - cgf_keyopt = `cfg_keygen`; + cgf_key_opt = `nostr_keygen`; }} > <p @@ -501,10 +497,10 @@ </p> </button> <button - class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${cgf_keyopt === `cfg_keyadd` ? `layer-1-surface-apply-active layer-1-raise-apply layer-1-ring-apply` : `bg-layer-1-surface`} el-re`} + class={`flex flex-col h-bold_button w-lo_${$app_lo} justify-center items-center rounded-touch ${cgf_key_opt === `nostr_keyadd` ? `layer-1-surface-apply-active layer-1-raise-apply layer-1-ring-apply` : `bg-layer-1-surface`} el-re`} onclick={async (ev) => { ev.stopPropagation(); - cgf_keyopt = `cfg_keyadd`; + cgf_key_opt = `nostr_keyadd`; }} > <p @@ -528,49 +524,53 @@ <div class={`flex flex-col w-full gap-6 justify-center items-center`} > - {#if cfg_profile_nostr_publickey} - <p - class={`font-sans font-[600] text-layer-0-glyph text-3xl`} - > - {`${$ls(`common.using_public_key`)}`} - </p> - <LabelDisplay - basis={{ + <p + class={`font-sans font-[600] text-layer-0-glyph text-3xl capitalize`} + > + {`${$ls(`icu.add_existing_*`, { value: `${$ls(`common.key`)}`.toLowerCase() })}`} + </p> + <EntryLine + bind:value={cfg_key_add_existing_val} + basis={{ + wrap: { + layer: 1, classes: `w-lo_${$app_lo}`, - label: { - classes: `pl-4 font-mono text-lg text-start truncate`, - value: - cfg_profile_nostr_publickey_npub || - cfg_profile_nostr_publickey, - }, style: `guide`, - }} - /> - {:else} - <p - class={`font-sans font-[600] text-layer-0-glyph text-3xl capitalize`} - > - {`${$ls(`icu.add_existing_*`, { value: `${$ls(`common.key`)}`.toLowerCase() })}`} - </p> - <Input - basis={{ - classes: `h-entry_guide w-lo_${$app_lo} bg-layer-1-surface layer-1-focus-surface rounded-touch font-mono text-lg placeholder:opacity-60 items-end text-center`, - id: fmt_id(`nostr:key:add`), - sync: true, + }, + el: { + classes: `font-sans text-[1.25rem] text-center placeholder:opacity-60`, + layer: 1, placeholder: `${$ls(`icu.enter_*`, { value: `nostr nsec/hex` })}`, - field: form_fields.profile_name, callback_keydown: async ({ key_s, el }) => { if (key_s) { el.blur(); await handle_continue(); } }, - }} - /> - {/if} + }, + }} + /> </div> </div> </div> + <div + class={`z-10 absolute max-m_0:bottom-0 bottom-10 left-0 flex flex-col w-full justify-center items-center`} + > + <ButtonLayoutPair + basis={{ + continue: { + label: `${$ls(`common.continue`)}`, + disabled: $carousel_index === 1 && !cgf_key_opt, + callback: async () => await handle_continue(), + }, + back: { + label: `${$ls(`common.back`)}`, + visible: $carousel_index > 0, + callback: async () => await handle_back(), + }, + }} + /> + </div> </div> </div> <div @@ -591,33 +591,63 @@ <p class={`font-sans font-[600] text-layer-0-glyph text-3xl`}> {`${$ls(`icu.add_*`, { value: `${$ls(`common.profile`)}` })}`} </p> - <EntryLineIdb - basis={{ - loading: cfg_profile_profilename_loading, - wrap: { - layer: 1, - classes: `w-lo_${$app_lo}`, - style: `guide`, - }, - el: { - classes: `font-sans text-[1.25rem] text-center placeholder:opacity-60`, - id: fmt_id(`nostr:profile`), - sync: true, - layer: 1, - placeholder: `${$ls(`icu.enter_*`, { value: `${$ls(`common.profile_name`)}`.toLowerCase() })}`, - field: form_fields.profile_name, - callback: async ({ pass }) => { - cfg_profile_profilename_valid = pass; + <div + class={`flex flex-col w-full gap-4 justify-center items-center`} + > + <EntryLine + bind:value={cfg_profile_name_val} + basis={{ + loading: cfg_profile_name_loading, + wrap: { + layer: 1, + classes: `w-lo_${$app_lo}`, + style: `guide`, }, - callback_keydown: async ({ key_s, el }) => { - if (key_s) { - el.blur(); - await handle_continue(); - } + el: { + classes: `font-sans text-[1.25rem] text-center placeholder:opacity-60`, + id: fmt_id(`nostr:profile`), + layer: 1, + placeholder: `${$ls(`icu.enter_*`, { value: `${$ls(`common.profile_name`)}`.toLowerCase() })}`, + field: form_fields.profile_name, + callback: async ({ pass }) => { + cfg_profile_name_valid = pass; + }, + callback_keydown: async ({ key_s, el }) => { + if (key_s) { + el.blur(); + await handle_continue(); + } + }, }, - }, - }} - /> + }} + /> + <div + class={`flex flex-row w-full gap-2 justify-center items-center`} + > + <input + type="checkbox" + bind:checked={cfg_profile_nip05_opt} + /> + <button + class={`flex flex-row justify-center items-center`} + onclick={async () => { + cfg_profile_nip05_opt = !cfg_profile_nip05_opt; + }} + > + <p + class={`font-sans font-[500] text-layer-0-glyph text-[14px] tracking-wide`} + > + {`${$ls(`common.create`)}`} + <span + class={`font-mono font-[600] tracking-tight px-[2px]`} + > + {`@radroots`} + </span> + {`${$ls(`common.nip05_address`)}`} + </p> + </button> + </div> + </div> </div> </div> <div @@ -673,7 +703,6 @@ </div> </div> </div> - <div class={`absolute max-m_0:bottom-0 bottom-10 left-0 flex flex-col w-full justify-center items-center`} > @@ -682,32 +711,17 @@ continue: { label: `${$ls(`common.continue`)}`, disabled: - ($carousel_index === 0 && - !cfg_profile_profilename_valid) || - ($carousel_index === 1 && !cfg_role), + // ($carousel_index === 0 && + // !cfg_profile_name_valid) || + $carousel_index === 1 && !cfg_role, callback: async () => await handle_continue(), }, back: { visible: true, - label: - $carousel_index === 0 - ? `${$ls(`common.skip`)}` - : `${$ls(`common.back`)}`, - callback: async () => { - if ($carousel_index === 0) { - const confirm = await gui.confirm({ - message: `${$ls(`notification.init.no_profile_option`)}`, - cancel: `${$ls(`icu.add_*`, { value: `${$ls(`common.profile`)}` })}`, - ok: `${$ls(`common.continue`)}`, - }); - if (confirm === false) - return void el_id( - fmt_id(`nostr:profile`), - )?.focus(); - return void carousel_inc(view); - } - await handle_back(); - }, + label: cfg_profile_name_skip + ? `${$ls(`common.skip`)}` + : `${$ls(`common.back`)}`, + callback: handle_back, }, }} /> diff --git a/app/tailwind.config.ts b/app/tailwind.config.ts @@ -9,7 +9,7 @@ const heights_responsive: Record<AppHeightsResponsiveIOS, string> = { nav_tabs_ios0: `80px`, nav_tabs_ios1: `120px`, nav_page_toolbar_ios0: `72px`, - nav_page_toolbar_ios1: `160px`, + nav_page_toolbar_ios1: `120px`, nav_page_header_ios0: `62px`, nav_page_header_ios1: `54px`, lo_bottom_button_ios0: `90px`, diff --git a/crates/core/src/keystore.rs b/crates/core/src/keystore.rs @@ -19,18 +19,18 @@ pub enum KeystoreError { Utf8Error(#[from] std::string::FromUtf8Error), #[error("Key error: {0}")] KeyError(#[from] nostr_sdk::key::Error), - #[error("Key not found")] + #[error("error.keystore.key_not_found")] KeyNotFound, } pub type KeystoreResult<T> = std::result::Result<T, KeystoreError>; fn get_keystore_path(data_dir: &std::path::Path) -> std::path::PathBuf { - data_dir.join("radroots.json") + data_dir.join("keystore.json") } fn get_keystore_key(data_dir: &std::path::Path) -> Vec<u8> { - let keystore_file = data_dir.join("radroots_keystore"); + let keystore_file = data_dir.join("keystore.key"); let keystore_key = if keystore_file.exists() { std::fs::read_to_string(&keystore_file) .map_err(KeystoreError::FileError) diff --git a/crates/tauri/.gitignore b/crates/tangle/.gitignore diff --git a/crates/tangle/Cargo.toml b/crates/tangle/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "tangle" +version = "0.0.1" +authors = ["Radroots Authors"] +license = "GPLv3" +edition = "2021" +rust-version = "1.77.2" + +[lib] +name = "tangle_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2.0.0", features = [] } + +[dependencies] +tauri = { version = "2.2.0", features = ["protocol-asset"] } +tauri-plugin-dialog = { version = "2.2.0" } +tauri-plugin-fs = { version = "2.2.0" } +tauri-plugin-geolocation = { path = "../../../lib/plugins-workspace/plugins/geolocation" } +tauri-plugin-http = { version = "2.2.0" } +tauri-plugin-notification = { version = "2.2.0" } +tauri-plugin-os = { version = "2.2.0" } +tauri-plugin-store = { version = "2.2.0" } +tauri-plugin-shell = { version = "2.2.0" } + +radroots_core = { path = "../core" } +radroots_model = { path = "../model" } + +serde = "1.0" +serde_json = "1.0" +sqlx = { version = "0.8.2", features = ["sqlite", "runtime-tokio"] } diff --git a/crates/tauri/LICENSE b/crates/tangle/LICENSE diff --git a/crates/tauri/build.rs b/crates/tangle/build.rs diff --git a/crates/tauri/capabilities/default.json b/crates/tangle/capabilities/default.json diff --git a/crates/tauri/capabilities/desktop.json b/crates/tangle/capabilities/desktop.json diff --git a/crates/tauri/capabilities/mobile.json b/crates/tangle/capabilities/mobile.json diff --git a/crates/tauri/icons/128x128.png b/crates/tangle/icons/128x128.png Binary files differ. diff --git a/crates/tauri/icons/128x128@2x.png b/crates/tangle/icons/128x128@2x.png Binary files differ. diff --git a/crates/tauri/icons/32x32.png b/crates/tangle/icons/32x32.png Binary files differ. diff --git a/crates/tauri/icons/Square107x107Logo.png b/crates/tangle/icons/Square107x107Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square142x142Logo.png b/crates/tangle/icons/Square142x142Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square150x150Logo.png b/crates/tangle/icons/Square150x150Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square284x284Logo.png b/crates/tangle/icons/Square284x284Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square30x30Logo.png b/crates/tangle/icons/Square30x30Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square310x310Logo.png b/crates/tangle/icons/Square310x310Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square44x44Logo.png b/crates/tangle/icons/Square44x44Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square71x71Logo.png b/crates/tangle/icons/Square71x71Logo.png Binary files differ. diff --git a/crates/tauri/icons/Square89x89Logo.png b/crates/tangle/icons/Square89x89Logo.png Binary files differ. diff --git a/crates/tauri/icons/StoreLogo.png b/crates/tangle/icons/StoreLogo.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-hdpi/ic_launcher.png b/crates/tangle/icons/android/mipmap-hdpi/ic_launcher.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/crates/tangle/icons/android/mipmap-hdpi/ic_launcher_foreground.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/crates/tangle/icons/android/mipmap-hdpi/ic_launcher_round.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-mdpi/ic_launcher.png b/crates/tangle/icons/android/mipmap-mdpi/ic_launcher.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/crates/tangle/icons/android/mipmap-mdpi/ic_launcher_foreground.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/crates/tangle/icons/android/mipmap-mdpi/ic_launcher_round.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/crates/tangle/icons/android/mipmap-xhdpi/ic_launcher.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/crates/tangle/icons/android/mipmap-xhdpi/ic_launcher_foreground.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/crates/tangle/icons/android/mipmap-xhdpi/ic_launcher_round.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/crates/tangle/icons/android/mipmap-xxhdpi/ic_launcher.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/crates/tangle/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/crates/tangle/icons/android/mipmap-xxhdpi/ic_launcher_round.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/crates/tangle/icons/android/mipmap-xxxhdpi/ic_launcher.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/crates/tangle/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png Binary files differ. diff --git a/crates/tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/crates/tangle/icons/android/mipmap-xxxhdpi/ic_launcher_round.png Binary files differ. diff --git a/crates/tangle/icons/icon.icns b/crates/tangle/icons/icon.icns Binary files differ. diff --git a/crates/tauri/icons/icon.ico b/crates/tangle/icons/icon.ico Binary files differ. diff --git a/crates/tauri/icons/icon.png b/crates/tangle/icons/icon.png Binary files differ. diff --git a/crates/tauri/migrations/down/0001_location_gcs.sql b/crates/tangle/migrations/down/0001_location_gcs.sql diff --git a/crates/tauri/migrations/down/0002_trade_product.sql b/crates/tangle/migrations/down/0002_trade_product.sql diff --git a/crates/tauri/migrations/down/0003_nostr_profile.sql b/crates/tangle/migrations/down/0003_nostr_profile.sql diff --git a/crates/tauri/migrations/down/0004_nostr_relay.sql b/crates/tangle/migrations/down/0004_nostr_relay.sql diff --git a/crates/tauri/migrations/down/0005_media_image.sql b/crates/tangle/migrations/down/0005_media_image.sql diff --git a/crates/tauri/migrations/down/0006_log_error.sql b/crates/tangle/migrations/down/0006_log_error.sql diff --git a/crates/tauri/migrations/down/0007_nostr_profile_relay.sql b/crates/tangle/migrations/down/0007_nostr_profile_relay.sql diff --git a/crates/tauri/migrations/down/0008_trade_product_location.sql b/crates/tangle/migrations/down/0008_trade_product_location.sql diff --git a/crates/tauri/migrations/down/0009_trade_product_media.sql b/crates/tangle/migrations/down/0009_trade_product_media.sql diff --git a/crates/tauri/migrations/up/0001_location_gcs.sql b/crates/tangle/migrations/up/0001_location_gcs.sql diff --git a/crates/tauri/migrations/up/0002_trade_product.sql b/crates/tangle/migrations/up/0002_trade_product.sql diff --git a/crates/tauri/migrations/up/0003_nostr_profile.sql b/crates/tangle/migrations/up/0003_nostr_profile.sql diff --git a/crates/tauri/migrations/up/0004_nostr_relay.sql b/crates/tangle/migrations/up/0004_nostr_relay.sql diff --git a/crates/tauri/migrations/up/0005_media_image.sql b/crates/tangle/migrations/up/0005_media_image.sql diff --git a/crates/tauri/migrations/up/0006_log_error.sql b/crates/tangle/migrations/up/0006_log_error.sql diff --git a/crates/tauri/migrations/up/0007_nostr_profile_relay.sql b/crates/tangle/migrations/up/0007_nostr_profile_relay.sql diff --git a/crates/tauri/migrations/up/0008_trade_product_location.sql b/crates/tangle/migrations/up/0008_trade_product_location.sql diff --git a/crates/tauri/migrations/up/0009_trade_product_media.sql b/crates/tangle/migrations/up/0009_trade_product_media.sql diff --git a/crates/tangle/src/app.rs b/crates/tangle/src/app.rs @@ -0,0 +1,24 @@ +use std::path::PathBuf; + +use radroots_model::types::DatabaseConnection; + +use crate::util; + +pub struct Tangle { + pub db: DatabaseConnection, + pub data_dir: PathBuf, + pub logs_dir: PathBuf, +} + +impl Tangle { + pub async fn new(data_dir: PathBuf, logs_dir: PathBuf) -> Self { + util::init_keyring(&data_dir).await; + let db = util::init_db(&data_dir).await; + + Self { + db, + data_dir, + logs_dir, + } + } +} diff --git a/crates/tangle/src/commands/keys.rs b/crates/tangle/src/commands/keys.rs @@ -0,0 +1,69 @@ +use radroots_core::{ + keystore, + nostr::keys::{ + lib_nostr_keys_gen, lib_nostr_keys_parse, lib_nostr_public_key_hex, + lib_nostr_secret_key_hex, + }, + types::{IResult, IResultList, IResultPass}, +}; + +use crate::app::Tangle; + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_gen(rr: tauri::State<'_, Tangle>) -> Result<IResult<String>, String> { + let keys = lib_nostr_keys_gen(); + keystore::key_add(&keys, &rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResult { + result: keys.public_key.to_hex(), + }) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_add( + secret_key: String, + rr: tauri::State<'_, Tangle>, +) -> Result<IResult<String>, String> { + let keys = lib_nostr_keys_parse(secret_key).map_err(|e| e.to_string())?; + keystore::key_add(&keys, &rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResult { + result: lib_nostr_public_key_hex(keys), + }) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_read( + public_key: String, + rr: tauri::State<'_, Tangle>, +) -> Result<IResult<String>, String> { + let keys = keystore::key_read(&public_key, &rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResult { + result: lib_nostr_secret_key_hex(keys), + }) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_read_all( + rr: tauri::State<'_, Tangle>, +) -> Result<IResultList<String>, String> { + let keystore_keys = keystore::keys_read_all(&rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResultList { + results: keystore_keys, + }) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_delete( + public_key: String, + rr: tauri::State<'_, Tangle>, +) -> Result<IResultPass, String> { + keystore::key_delete(&public_key, &rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResultPass { pass: true }) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn keys_nostr_keystore_reset( + rr: tauri::State<'_, Tangle>, +) -> Result<IResultPass, String> { + keystore::reset(&rr.data_dir).map_err(|e| e.to_string())?; + Ok(IResultPass { pass: true }) +} diff --git a/crates/tauri/src/commands/mod.rs b/crates/tangle/src/commands/mod.rs diff --git a/crates/tangle/src/commands/model/location_gcs.rs b/crates/tangle/src/commands/model/location_gcs.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::location_gcs::{lib_model_location_gcs_create, ILocationGcsCreate, ILocationGcsCreateResolve, lib_model_location_gcs_read, ILocationGcsRead, ILocationGcsReadResolve, lib_model_location_gcs_read_list, ILocationGcsReadList, ILocationGcsReadListResolve, lib_model_location_gcs_delete, ILocationGcsDelete, ILocationGcsDeleteResolve, lib_model_location_gcs_update, ILocationGcsUpdate, ILocationGcsUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_location_gcs_create( + state: tauri::State<'_, Tangle>, + args: ILocationGcsCreate, +) -> Result<ILocationGcsCreateResolve, IError> { + match lib_model_location_gcs_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_location_gcs_read( + state: tauri::State<'_, Tangle>, + args: ILocationGcsRead, +) -> Result<ILocationGcsReadResolve, IError> { + match lib_model_location_gcs_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_location_gcs_read_list( + state: tauri::State<'_, Tangle>, + args: ILocationGcsReadList, +) -> Result<ILocationGcsReadListResolve, IError> { + match lib_model_location_gcs_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_location_gcs_update( + state: tauri::State<'_, Tangle>, + args: ILocationGcsUpdate, +) -> Result<ILocationGcsUpdateResolve, IError> { + match lib_model_location_gcs_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_location_gcs_delete( + state: tauri::State<'_, Tangle>, + args: ILocationGcsDelete, +) -> Result<ILocationGcsDeleteResolve, IError> { + match lib_model_location_gcs_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/log_error.rs b/crates/tangle/src/commands/model/log_error.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::log_error::{lib_model_log_error_create, ILogErrorCreate, ILogErrorCreateResolve, lib_model_log_error_read, ILogErrorRead, ILogErrorReadResolve, lib_model_log_error_read_list, ILogErrorReadList, ILogErrorReadListResolve, lib_model_log_error_delete, ILogErrorDelete, ILogErrorDeleteResolve, lib_model_log_error_update, ILogErrorUpdate, ILogErrorUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_log_error_create( + state: tauri::State<'_, Tangle>, + args: ILogErrorCreate, +) -> Result<ILogErrorCreateResolve, IError> { + match lib_model_log_error_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_log_error_read( + state: tauri::State<'_, Tangle>, + args: ILogErrorRead, +) -> Result<ILogErrorReadResolve, IError> { + match lib_model_log_error_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_log_error_read_list( + state: tauri::State<'_, Tangle>, + args: ILogErrorReadList, +) -> Result<ILogErrorReadListResolve, IError> { + match lib_model_log_error_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_log_error_update( + state: tauri::State<'_, Tangle>, + args: ILogErrorUpdate, +) -> Result<ILogErrorUpdateResolve, IError> { + match lib_model_log_error_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_log_error_delete( + state: tauri::State<'_, Tangle>, + args: ILogErrorDelete, +) -> Result<ILogErrorDeleteResolve, IError> { + match lib_model_log_error_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/media_image.rs b/crates/tangle/src/commands/model/media_image.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::media_image::{lib_model_media_image_create, IMediaImageCreate, IMediaImageCreateResolve, lib_model_media_image_read, IMediaImageRead, IMediaImageReadResolve, lib_model_media_image_read_list, IMediaImageReadList, IMediaImageReadListResolve, lib_model_media_image_delete, IMediaImageDelete, IMediaImageDeleteResolve, lib_model_media_image_update, IMediaImageUpdate, IMediaImageUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_media_image_create( + state: tauri::State<'_, Tangle>, + args: IMediaImageCreate, +) -> Result<IMediaImageCreateResolve, IError> { + match lib_model_media_image_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_media_image_read( + state: tauri::State<'_, Tangle>, + args: IMediaImageRead, +) -> Result<IMediaImageReadResolve, IError> { + match lib_model_media_image_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_media_image_read_list( + state: tauri::State<'_, Tangle>, + args: IMediaImageReadList, +) -> Result<IMediaImageReadListResolve, IError> { + match lib_model_media_image_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_media_image_update( + state: tauri::State<'_, Tangle>, + args: IMediaImageUpdate, +) -> Result<IMediaImageUpdateResolve, IError> { + match lib_model_media_image_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_media_image_delete( + state: tauri::State<'_, Tangle>, + args: IMediaImageDelete, +) -> Result<IMediaImageDeleteResolve, IError> { + match lib_model_media_image_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/mod.rs b/crates/tangle/src/commands/model/mod.rs @@ -0,0 +1,21 @@ +use crate::app::Tangle; +use radroots_core::types::{IError, IResultPass}; +use radroots_model::tables::lib_model_tables_reset; + +pub(crate) mod location_gcs; +pub(crate) mod log_error; +pub(crate) mod media_image; +pub(crate) mod nostr_profile; +pub(crate) mod nostr_profile_relay; +pub(crate) mod nostr_relay; +pub(crate) mod trade_product; +pub(crate) mod trade_product_location; +pub(crate) mod trade_product_media; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_tables_reset(state: tauri::State<'_, Tangle>) -> Result<IResultPass, IError> { + match lib_model_tables_reset(&state.db).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} diff --git a/crates/tangle/src/commands/model/nostr_profile.rs b/crates/tangle/src/commands/model/nostr_profile.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::nostr_profile::{lib_model_nostr_profile_create, INostrProfileCreate, INostrProfileCreateResolve, lib_model_nostr_profile_read, INostrProfileRead, INostrProfileReadResolve, lib_model_nostr_profile_read_list, INostrProfileReadList, INostrProfileReadListResolve, lib_model_nostr_profile_delete, INostrProfileDelete, INostrProfileDeleteResolve, lib_model_nostr_profile_update, INostrProfileUpdate, INostrProfileUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_create( + state: tauri::State<'_, Tangle>, + args: INostrProfileCreate, +) -> Result<INostrProfileCreateResolve, IError> { + match lib_model_nostr_profile_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_read( + state: tauri::State<'_, Tangle>, + args: INostrProfileRead, +) -> Result<INostrProfileReadResolve, IError> { + match lib_model_nostr_profile_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_read_list( + state: tauri::State<'_, Tangle>, + args: INostrProfileReadList, +) -> Result<INostrProfileReadListResolve, IError> { + match lib_model_nostr_profile_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_update( + state: tauri::State<'_, Tangle>, + args: INostrProfileUpdate, +) -> Result<INostrProfileUpdateResolve, IError> { + match lib_model_nostr_profile_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_delete( + state: tauri::State<'_, Tangle>, + args: INostrProfileDelete, +) -> Result<INostrProfileDeleteResolve, IError> { + match lib_model_nostr_profile_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/nostr_profile_relay.rs b/crates/tangle/src/commands/model/nostr_profile_relay.rs @@ -0,0 +1,28 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::tables::nostr_profile_relay::{ + lib_model_nostr_profile_relay_set, lib_model_nostr_profile_relay_unset, + INostrProfileRelayRelation, INostrProfileRelayResolve, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_relay_set( + state: tauri::State<'_, Tangle>, + args: INostrProfileRelayRelation, +) -> Result<INostrProfileRelayResolve, IError> { + match lib_model_nostr_profile_relay_set(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_profile_relay_unset( + state: tauri::State<'_, Tangle>, + args: INostrProfileRelayRelation, +) -> Result<INostrProfileRelayResolve, IError> { + match lib_model_nostr_profile_relay_unset(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/nostr_relay.rs b/crates/tangle/src/commands/model/nostr_relay.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::nostr_relay::{lib_model_nostr_relay_create, INostrRelayCreate, INostrRelayCreateResolve, lib_model_nostr_relay_read, INostrRelayRead, INostrRelayReadResolve, lib_model_nostr_relay_read_list, INostrRelayReadList, INostrRelayReadListResolve, lib_model_nostr_relay_delete, INostrRelayDelete, INostrRelayDeleteResolve, lib_model_nostr_relay_update, INostrRelayUpdate, INostrRelayUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_relay_create( + state: tauri::State<'_, Tangle>, + args: INostrRelayCreate, +) -> Result<INostrRelayCreateResolve, IError> { + match lib_model_nostr_relay_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_relay_read( + state: tauri::State<'_, Tangle>, + args: INostrRelayRead, +) -> Result<INostrRelayReadResolve, IError> { + match lib_model_nostr_relay_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_relay_read_list( + state: tauri::State<'_, Tangle>, + args: INostrRelayReadList, +) -> Result<INostrRelayReadListResolve, IError> { + match lib_model_nostr_relay_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_relay_update( + state: tauri::State<'_, Tangle>, + args: INostrRelayUpdate, +) -> Result<INostrRelayUpdateResolve, IError> { + match lib_model_nostr_relay_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_nostr_relay_delete( + state: tauri::State<'_, Tangle>, + args: INostrRelayDelete, +) -> Result<INostrRelayDeleteResolve, IError> { + match lib_model_nostr_relay_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/trade_product.rs b/crates/tangle/src/commands/model/trade_product.rs @@ -0,0 +1,60 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::{ + tables::trade_product::{lib_model_trade_product_create, ITradeProductCreate, ITradeProductCreateResolve, lib_model_trade_product_read, ITradeProductRead, ITradeProductReadResolve, lib_model_trade_product_read_list, ITradeProductReadList, ITradeProductReadListResolve, lib_model_trade_product_delete, ITradeProductDelete, ITradeProductDeleteResolve, lib_model_trade_product_update, ITradeProductUpdate, ITradeProductUpdateResolve}, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_create( + state: tauri::State<'_, Tangle>, + args: ITradeProductCreate, +) -> Result<ITradeProductCreateResolve, IError> { + match lib_model_trade_product_create(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_read( + state: tauri::State<'_, Tangle>, + args: ITradeProductRead, +) -> Result<ITradeProductReadResolve, IError> { + match lib_model_trade_product_read(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_read_list( + state: tauri::State<'_, Tangle>, + args: ITradeProductReadList, +) -> Result<ITradeProductReadListResolve, IError> { + match lib_model_trade_product_read_list(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_update( + state: tauri::State<'_, Tangle>, + args: ITradeProductUpdate, +) -> Result<ITradeProductUpdateResolve, IError> { + match lib_model_trade_product_update(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_delete( + state: tauri::State<'_, Tangle>, + args: ITradeProductDelete, +) -> Result<ITradeProductDeleteResolve, IError> { + match lib_model_trade_product_delete(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/trade_product_location.rs b/crates/tangle/src/commands/model/trade_product_location.rs @@ -0,0 +1,28 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::tables::trade_product_location::{ + lib_model_trade_product_location_set, lib_model_trade_product_location_unset, + ITradeProductLocationRelation, ITradeProductLocationResolve, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_location_set( + state: tauri::State<'_, Tangle>, + args: ITradeProductLocationRelation, +) -> Result<ITradeProductLocationResolve, IError> { + match lib_model_trade_product_location_set(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_location_unset( + state: tauri::State<'_, Tangle>, + args: ITradeProductLocationRelation, +) -> Result<ITradeProductLocationResolve, IError> { + match lib_model_trade_product_location_unset(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/commands/model/trade_product_media.rs b/crates/tangle/src/commands/model/trade_product_media.rs @@ -0,0 +1,28 @@ +use crate::app::Tangle; +use radroots_core::types::IError; +use radroots_model::tables::trade_product_media::{ + lib_model_trade_product_media_set, lib_model_trade_product_media_unset, + ITradeProductMediaRelation, ITradeProductMediaResolve, +}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_media_set( + state: tauri::State<'_, Tangle>, + args: ITradeProductMediaRelation, +) -> Result<ITradeProductMediaResolve, IError> { + match lib_model_trade_product_media_set(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn model_trade_product_media_unset( + state: tauri::State<'_, Tangle>, + args: ITradeProductMediaRelation, +) -> Result<ITradeProductMediaResolve, IError> { + match lib_model_trade_product_media_unset(&state.db, args).await { + Ok(result) => Ok(result), + Err(e) => Err(IError { err: e.to_string() }), + } +} +\ No newline at end of file diff --git a/crates/tangle/src/lib.rs b/crates/tangle/src/lib.rs @@ -0,0 +1,134 @@ +pub mod app; +pub mod commands; +pub mod util; + +use app::Tangle; +use commands::keys::{ + keys_nostr_add, keys_nostr_delete, keys_nostr_gen, keys_nostr_keystore_reset, keys_nostr_read, + keys_nostr_read_all, +}; +use commands::model::location_gcs::{ + model_location_gcs_create, model_location_gcs_delete, model_location_gcs_read, + model_location_gcs_read_list, model_location_gcs_update, + }; +use commands::model::log_error::{ + model_log_error_create, model_log_error_delete, model_log_error_read, + model_log_error_read_list, model_log_error_update, + }; +use commands::model::media_image::{ + model_media_image_create, model_media_image_delete, model_media_image_read, + model_media_image_read_list, model_media_image_update, + }; +use commands::model::model_tables_reset; +use commands::model::nostr_profile::{ + model_nostr_profile_create, model_nostr_profile_delete, model_nostr_profile_read, + model_nostr_profile_read_list, model_nostr_profile_update, + }; +use commands::model::nostr_profile_relay::{ + model_nostr_profile_relay_set, model_nostr_profile_relay_unset, + }; +use commands::model::nostr_relay::{ + model_nostr_relay_create, model_nostr_relay_delete, model_nostr_relay_read, + model_nostr_relay_read_list, model_nostr_relay_update, + }; +use commands::model::trade_product::{ + model_trade_product_create, model_trade_product_delete, model_trade_product_read, + model_trade_product_read_list, model_trade_product_update, + }; +use commands::model::trade_product_location::{ + model_trade_product_location_set, model_trade_product_location_unset, + }; +use commands::model::trade_product_media::{ + model_trade_product_media_set, model_trade_product_media_unset, + }; +use std::path::PathBuf; +use tauri::Manager; + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_fs::init()) + .plugin(tauri_plugin_geolocation::init()) + .plugin(tauri_plugin_http::init()) + .plugin(tauri_plugin_notification::init()) + .plugin(tauri_plugin_os::init()) + .plugin(tauri_plugin_store::Builder::new().build()) + .setup(|app| { + let data_dir = app + .handle() + .path() + .app_data_dir() + .expect("Failed to resolve app data dir"); + + let logs_dir = app.handle().path().app_log_dir().unwrap(); + + let fmt_data_dir = if cfg!(dev) { + PathBuf::from(format!("{}/dev", data_dir.to_string_lossy())) + } else { + PathBuf::from(format!("{}/release", data_dir.to_string_lossy())) + }; + + let fmt_logs_dir = if cfg!(dev) { + PathBuf::from(format!("{}/dev", logs_dir.to_string_lossy())) + } else { + PathBuf::from(format!("{}/release", logs_dir.to_string_lossy())) + }; + + tauri::async_runtime::block_on(async move { + let tangle = Tangle::new(fmt_data_dir, fmt_logs_dir).await; + app.manage(tangle); + }); + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + // %model% + model_location_gcs_create, + model_location_gcs_delete, + model_location_gcs_read, + model_location_gcs_read_list, + model_location_gcs_update, + model_log_error_create, + model_log_error_delete, + model_log_error_read, + model_log_error_read_list, + model_log_error_update, + model_media_image_create, + model_media_image_delete, + model_media_image_read, + model_media_image_read_list, + model_media_image_update, + model_nostr_profile_create, + model_nostr_profile_delete, + model_nostr_profile_read, + model_nostr_profile_read_list, + model_nostr_profile_relay_set, + model_nostr_profile_relay_unset, + model_nostr_profile_update, + model_nostr_relay_create, + model_nostr_relay_delete, + model_nostr_relay_read, + model_nostr_relay_read_list, + model_nostr_relay_update, + model_tables_reset, + model_trade_product_create, + model_trade_product_delete, + model_trade_product_location_set, + model_trade_product_location_unset, + model_trade_product_media_set, + model_trade_product_media_unset, + model_trade_product_read, + model_trade_product_read_list, + model_trade_product_update, + // %model% + keys_nostr_gen, + keys_nostr_add, + keys_nostr_read, + keys_nostr_read_all, + keys_nostr_delete, + keys_nostr_keystore_reset + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/crates/tangle/src/main.rs b/crates/tangle/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + tangle_lib::run(); +} diff --git a/crates/tauri/src/util.rs b/crates/tangle/src/util.rs diff --git a/crates/tangle/tauri.conf.json b/crates/tangle/tauri.conf.json @@ -0,0 +1,33 @@ +{ + "$schema": "../../node_modules/@tauri-apps/cli/config.schema.json", + "identifier": "tangle.radroots.app", + "productName": "Tangle", + "mainBinaryName": "tangle", + "build": { + "frontendDist": "../../app/build", + "devUrl": "http://localhost:3000", + "beforeDevCommand": "cd app && pnpm run dev:hmr", + "beforeBuildCommand": "cd app && pnpm run build" + }, + "app": { + "windows": [ + { + "title": "tangle | rad roots", + "resizable": false, + "fullscreen": true, + "visible": true + } + ] + }, + "bundle": { + "active": false, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} +\ No newline at end of file diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml @@ -1,32 +0,0 @@ -[package] -name = "radroots" -version = "0.0.1" -authors = ["Radroots Authors"] -license = "GPLv3" -edition = "2021" -rust-version = "1.77.2" - -[lib] -name = "radroots_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2.0.0", features = [] } - -[dependencies] -tauri = { version = "2.2.0", features = ["protocol-asset"] } -tauri-plugin-dialog = { version = "2.2.0" } -tauri-plugin-fs = { version = "2.2.0" } -tauri-plugin-geolocation = { path = "../../../lib/plugins-workspace/plugins/geolocation" } -tauri-plugin-http = { version = "2.2.0" } -tauri-plugin-notification = { version = "2.2.0" } -tauri-plugin-os = { version = "2.2.0" } -tauri-plugin-store = { version = "2.2.0" } -tauri-plugin-shell = { version = "2.2.0" } - -radroots_core = { path = "../core" } -radroots_model = { path = "../model" } - -serde = "1.0" -serde_json = "1.0" -sqlx = { version = "0.8.2", features = ["sqlite", "runtime-tokio"] } diff --git a/crates/tauri/icons/icon.icns b/crates/tauri/icons/icon.icns Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-20x20@1x.png b/crates/tauri/icons/ios/AppIcon-20x20@1x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-20x20@2x-1.png b/crates/tauri/icons/ios/AppIcon-20x20@2x-1.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-20x20@2x.png b/crates/tauri/icons/ios/AppIcon-20x20@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-20x20@3x.png b/crates/tauri/icons/ios/AppIcon-20x20@3x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-29x29@1x.png b/crates/tauri/icons/ios/AppIcon-29x29@1x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-29x29@2x-1.png b/crates/tauri/icons/ios/AppIcon-29x29@2x-1.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-29x29@2x.png b/crates/tauri/icons/ios/AppIcon-29x29@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-29x29@3x.png b/crates/tauri/icons/ios/AppIcon-29x29@3x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-40x40@1x.png b/crates/tauri/icons/ios/AppIcon-40x40@1x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-40x40@2x-1.png b/crates/tauri/icons/ios/AppIcon-40x40@2x-1.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-40x40@2x.png b/crates/tauri/icons/ios/AppIcon-40x40@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-40x40@3x.png b/crates/tauri/icons/ios/AppIcon-40x40@3x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-512@2x.png b/crates/tauri/icons/ios/AppIcon-512@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-60x60@2x.png b/crates/tauri/icons/ios/AppIcon-60x60@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-60x60@3x.png b/crates/tauri/icons/ios/AppIcon-60x60@3x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-76x76@1x.png b/crates/tauri/icons/ios/AppIcon-76x76@1x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-76x76@2x.png b/crates/tauri/icons/ios/AppIcon-76x76@2x.png Binary files differ. diff --git a/crates/tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/crates/tauri/icons/ios/AppIcon-83.5x83.5@2x.png Binary files differ. diff --git a/crates/tauri/src/commands/keys.rs b/crates/tauri/src/commands/keys.rs @@ -1,74 +0,0 @@ -use radroots_core::{ - keystore, - nostr::keys::{ - lib_nostr_keys_gen, lib_nostr_keys_parse, lib_nostr_public_key_hex, - lib_nostr_secret_key_hex, - }, - types::{IResult, IResultList, IResultPass}, -}; - -use crate::radroots::Radroots; - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_gen(rr: tauri::State<'_, Radroots>) -> Result<IResult<String>, String> { - let keys = lib_nostr_keys_gen(); - keystore::key_add(&keys, &rr.data_dir) - .map_err(|e| format!("Failed to create private key: {}", e))?; - Ok(IResult { - result: keys.public_key.to_hex(), - }) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_add( - secret_key: String, - rr: tauri::State<'_, Radroots>, -) -> Result<IResult<String>, String> { - let keys = lib_nostr_keys_parse(secret_key).map_err(|e| e.to_string())?; - keystore::key_add(&keys, &rr.data_dir) - .map_err(|e| format!("Failed to add private key: {}", e))?; - Ok(IResult { - result: lib_nostr_public_key_hex(keys), - }) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_read( - public_key: String, - rr: tauri::State<'_, Radroots>, -) -> Result<IResult<String>, String> { - let keys = keystore::key_read(&public_key, &rr.data_dir) - .map_err(|e| format!("Failed to read private key: {}", e))?; - Ok(IResult { - result: lib_nostr_secret_key_hex(keys), - }) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_read_all( - rr: tauri::State<'_, Radroots>, -) -> Result<IResultList<String>, String> { - let keystore_keys = keystore::keys_read_all(&rr.data_dir) - .map_err(|e| format!("Failed to read keystore: {}", e))?; - Ok(IResultList { - results: keystore_keys, - }) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_delete( - public_key: String, - rr: tauri::State<'_, Radroots>, -) -> Result<IResultPass, String> { - keystore::key_delete(&public_key, &rr.data_dir) - .map_err(|e| format!("Failed to delete private key: {}", e))?; - Ok(IResultPass { pass: true }) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn keys_nostr_keystore_reset( - rr: tauri::State<'_, Radroots>, -) -> Result<IResultPass, String> { - keystore::reset(&rr.data_dir).map_err(|e| format!("Failed to reset keystore: {}", e))?; - Ok(IResultPass { pass: true }) -} diff --git a/crates/tauri/src/commands/model/location_gcs.rs b/crates/tauri/src/commands/model/location_gcs.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::location_gcs::{lib_model_location_gcs_create, ILocationGcsCreate, ILocationGcsCreateResolve, lib_model_location_gcs_read, ILocationGcsRead, ILocationGcsReadResolve, lib_model_location_gcs_read_list, ILocationGcsReadList, ILocationGcsReadListResolve, lib_model_location_gcs_delete, ILocationGcsDelete, ILocationGcsDeleteResolve, lib_model_location_gcs_update, ILocationGcsUpdate, ILocationGcsUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_location_gcs_create( - state: tauri::State<'_, Radroots>, - args: ILocationGcsCreate, -) -> Result<ILocationGcsCreateResolve, IError> { - match lib_model_location_gcs_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_location_gcs_read( - state: tauri::State<'_, Radroots>, - args: ILocationGcsRead, -) -> Result<ILocationGcsReadResolve, IError> { - match lib_model_location_gcs_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_location_gcs_read_list( - state: tauri::State<'_, Radroots>, - args: ILocationGcsReadList, -) -> Result<ILocationGcsReadListResolve, IError> { - match lib_model_location_gcs_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_location_gcs_update( - state: tauri::State<'_, Radroots>, - args: ILocationGcsUpdate, -) -> Result<ILocationGcsUpdateResolve, IError> { - match lib_model_location_gcs_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_location_gcs_delete( - state: tauri::State<'_, Radroots>, - args: ILocationGcsDelete, -) -> Result<ILocationGcsDeleteResolve, IError> { - match lib_model_location_gcs_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/log_error.rs b/crates/tauri/src/commands/model/log_error.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::log_error::{lib_model_log_error_create, ILogErrorCreate, ILogErrorCreateResolve, lib_model_log_error_read, ILogErrorRead, ILogErrorReadResolve, lib_model_log_error_read_list, ILogErrorReadList, ILogErrorReadListResolve, lib_model_log_error_delete, ILogErrorDelete, ILogErrorDeleteResolve, lib_model_log_error_update, ILogErrorUpdate, ILogErrorUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_log_error_create( - state: tauri::State<'_, Radroots>, - args: ILogErrorCreate, -) -> Result<ILogErrorCreateResolve, IError> { - match lib_model_log_error_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_log_error_read( - state: tauri::State<'_, Radroots>, - args: ILogErrorRead, -) -> Result<ILogErrorReadResolve, IError> { - match lib_model_log_error_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_log_error_read_list( - state: tauri::State<'_, Radroots>, - args: ILogErrorReadList, -) -> Result<ILogErrorReadListResolve, IError> { - match lib_model_log_error_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_log_error_update( - state: tauri::State<'_, Radroots>, - args: ILogErrorUpdate, -) -> Result<ILogErrorUpdateResolve, IError> { - match lib_model_log_error_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_log_error_delete( - state: tauri::State<'_, Radroots>, - args: ILogErrorDelete, -) -> Result<ILogErrorDeleteResolve, IError> { - match lib_model_log_error_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/media_image.rs b/crates/tauri/src/commands/model/media_image.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::media_image::{lib_model_media_image_create, IMediaImageCreate, IMediaImageCreateResolve, lib_model_media_image_read, IMediaImageRead, IMediaImageReadResolve, lib_model_media_image_read_list, IMediaImageReadList, IMediaImageReadListResolve, lib_model_media_image_delete, IMediaImageDelete, IMediaImageDeleteResolve, lib_model_media_image_update, IMediaImageUpdate, IMediaImageUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_media_image_create( - state: tauri::State<'_, Radroots>, - args: IMediaImageCreate, -) -> Result<IMediaImageCreateResolve, IError> { - match lib_model_media_image_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_media_image_read( - state: tauri::State<'_, Radroots>, - args: IMediaImageRead, -) -> Result<IMediaImageReadResolve, IError> { - match lib_model_media_image_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_media_image_read_list( - state: tauri::State<'_, Radroots>, - args: IMediaImageReadList, -) -> Result<IMediaImageReadListResolve, IError> { - match lib_model_media_image_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_media_image_update( - state: tauri::State<'_, Radroots>, - args: IMediaImageUpdate, -) -> Result<IMediaImageUpdateResolve, IError> { - match lib_model_media_image_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_media_image_delete( - state: tauri::State<'_, Radroots>, - args: IMediaImageDelete, -) -> Result<IMediaImageDeleteResolve, IError> { - match lib_model_media_image_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/mod.rs b/crates/tauri/src/commands/model/mod.rs @@ -1,21 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::{IError, IResultPass}; -use radroots_model::tables::lib_model_tables_reset; - -pub(crate) mod location_gcs; -pub(crate) mod log_error; -pub(crate) mod media_image; -pub(crate) mod nostr_profile; -pub(crate) mod nostr_profile_relay; -pub(crate) mod nostr_relay; -pub(crate) mod trade_product; -pub(crate) mod trade_product_location; -pub(crate) mod trade_product_media; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_tables_reset(state: tauri::State<'_, Radroots>) -> Result<IResultPass, IError> { - match lib_model_tables_reset(&state.db).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} diff --git a/crates/tauri/src/commands/model/nostr_profile.rs b/crates/tauri/src/commands/model/nostr_profile.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::nostr_profile::{lib_model_nostr_profile_create, INostrProfileCreate, INostrProfileCreateResolve, lib_model_nostr_profile_read, INostrProfileRead, INostrProfileReadResolve, lib_model_nostr_profile_read_list, INostrProfileReadList, INostrProfileReadListResolve, lib_model_nostr_profile_delete, INostrProfileDelete, INostrProfileDeleteResolve, lib_model_nostr_profile_update, INostrProfileUpdate, INostrProfileUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_create( - state: tauri::State<'_, Radroots>, - args: INostrProfileCreate, -) -> Result<INostrProfileCreateResolve, IError> { - match lib_model_nostr_profile_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_read( - state: tauri::State<'_, Radroots>, - args: INostrProfileRead, -) -> Result<INostrProfileReadResolve, IError> { - match lib_model_nostr_profile_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_read_list( - state: tauri::State<'_, Radroots>, - args: INostrProfileReadList, -) -> Result<INostrProfileReadListResolve, IError> { - match lib_model_nostr_profile_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_update( - state: tauri::State<'_, Radroots>, - args: INostrProfileUpdate, -) -> Result<INostrProfileUpdateResolve, IError> { - match lib_model_nostr_profile_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_delete( - state: tauri::State<'_, Radroots>, - args: INostrProfileDelete, -) -> Result<INostrProfileDeleteResolve, IError> { - match lib_model_nostr_profile_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/nostr_profile_relay.rs b/crates/tauri/src/commands/model/nostr_profile_relay.rs @@ -1,28 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::tables::nostr_profile_relay::{ - lib_model_nostr_profile_relay_set, lib_model_nostr_profile_relay_unset, - INostrProfileRelayRelation, INostrProfileRelayResolve, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_relay_set( - state: tauri::State<'_, Radroots>, - args: INostrProfileRelayRelation, -) -> Result<INostrProfileRelayResolve, IError> { - match lib_model_nostr_profile_relay_set(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_profile_relay_unset( - state: tauri::State<'_, Radroots>, - args: INostrProfileRelayRelation, -) -> Result<INostrProfileRelayResolve, IError> { - match lib_model_nostr_profile_relay_unset(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/nostr_relay.rs b/crates/tauri/src/commands/model/nostr_relay.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::nostr_relay::{lib_model_nostr_relay_create, INostrRelayCreate, INostrRelayCreateResolve, lib_model_nostr_relay_read, INostrRelayRead, INostrRelayReadResolve, lib_model_nostr_relay_read_list, INostrRelayReadList, INostrRelayReadListResolve, lib_model_nostr_relay_delete, INostrRelayDelete, INostrRelayDeleteResolve, lib_model_nostr_relay_update, INostrRelayUpdate, INostrRelayUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_relay_create( - state: tauri::State<'_, Radroots>, - args: INostrRelayCreate, -) -> Result<INostrRelayCreateResolve, IError> { - match lib_model_nostr_relay_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_relay_read( - state: tauri::State<'_, Radroots>, - args: INostrRelayRead, -) -> Result<INostrRelayReadResolve, IError> { - match lib_model_nostr_relay_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_relay_read_list( - state: tauri::State<'_, Radroots>, - args: INostrRelayReadList, -) -> Result<INostrRelayReadListResolve, IError> { - match lib_model_nostr_relay_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_relay_update( - state: tauri::State<'_, Radroots>, - args: INostrRelayUpdate, -) -> Result<INostrRelayUpdateResolve, IError> { - match lib_model_nostr_relay_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_nostr_relay_delete( - state: tauri::State<'_, Radroots>, - args: INostrRelayDelete, -) -> Result<INostrRelayDeleteResolve, IError> { - match lib_model_nostr_relay_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/trade_product.rs b/crates/tauri/src/commands/model/trade_product.rs @@ -1,60 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::{ - tables::trade_product::{lib_model_trade_product_create, ITradeProductCreate, ITradeProductCreateResolve, lib_model_trade_product_read, ITradeProductRead, ITradeProductReadResolve, lib_model_trade_product_read_list, ITradeProductReadList, ITradeProductReadListResolve, lib_model_trade_product_delete, ITradeProductDelete, ITradeProductDeleteResolve, lib_model_trade_product_update, ITradeProductUpdate, ITradeProductUpdateResolve}, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_create( - state: tauri::State<'_, Radroots>, - args: ITradeProductCreate, -) -> Result<ITradeProductCreateResolve, IError> { - match lib_model_trade_product_create(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_read( - state: tauri::State<'_, Radroots>, - args: ITradeProductRead, -) -> Result<ITradeProductReadResolve, IError> { - match lib_model_trade_product_read(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_read_list( - state: tauri::State<'_, Radroots>, - args: ITradeProductReadList, -) -> Result<ITradeProductReadListResolve, IError> { - match lib_model_trade_product_read_list(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_update( - state: tauri::State<'_, Radroots>, - args: ITradeProductUpdate, -) -> Result<ITradeProductUpdateResolve, IError> { - match lib_model_trade_product_update(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_delete( - state: tauri::State<'_, Radroots>, - args: ITradeProductDelete, -) -> Result<ITradeProductDeleteResolve, IError> { - match lib_model_trade_product_delete(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/trade_product_location.rs b/crates/tauri/src/commands/model/trade_product_location.rs @@ -1,28 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::tables::trade_product_location::{ - lib_model_trade_product_location_set, lib_model_trade_product_location_unset, - ITradeProductLocationRelation, ITradeProductLocationResolve, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_location_set( - state: tauri::State<'_, Radroots>, - args: ITradeProductLocationRelation, -) -> Result<ITradeProductLocationResolve, IError> { - match lib_model_trade_product_location_set(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_location_unset( - state: tauri::State<'_, Radroots>, - args: ITradeProductLocationRelation, -) -> Result<ITradeProductLocationResolve, IError> { - match lib_model_trade_product_location_unset(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/commands/model/trade_product_media.rs b/crates/tauri/src/commands/model/trade_product_media.rs @@ -1,28 +0,0 @@ -use crate::radroots::Radroots; -use radroots_core::types::IError; -use radroots_model::tables::trade_product_media::{ - lib_model_trade_product_media_set, lib_model_trade_product_media_unset, - ITradeProductMediaRelation, ITradeProductMediaResolve, -}; - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_media_set( - state: tauri::State<'_, Radroots>, - args: ITradeProductMediaRelation, -) -> Result<ITradeProductMediaResolve, IError> { - match lib_model_trade_product_media_set(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn model_trade_product_media_unset( - state: tauri::State<'_, Radroots>, - args: ITradeProductMediaRelation, -) -> Result<ITradeProductMediaResolve, IError> { - match lib_model_trade_product_media_unset(&state.db, args).await { - Ok(result) => Ok(result), - Err(e) => Err(IError { err: e.to_string() }), - } -} -\ No newline at end of file diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs @@ -1,134 +0,0 @@ -pub mod commands; -pub mod radroots; -pub mod util; - -use commands::keys::{ - keys_nostr_add, keys_nostr_delete, keys_nostr_gen, keys_nostr_keystore_reset, keys_nostr_read, - keys_nostr_read_all, -}; -use commands::model::location_gcs::{ - model_location_gcs_create, model_location_gcs_delete, model_location_gcs_read, - model_location_gcs_read_list, model_location_gcs_update, - }; -use commands::model::log_error::{ - model_log_error_create, model_log_error_delete, model_log_error_read, - model_log_error_read_list, model_log_error_update, - }; -use commands::model::media_image::{ - model_media_image_create, model_media_image_delete, model_media_image_read, - model_media_image_read_list, model_media_image_update, - }; -use commands::model::model_tables_reset; -use commands::model::nostr_profile::{ - model_nostr_profile_create, model_nostr_profile_delete, model_nostr_profile_read, - model_nostr_profile_read_list, model_nostr_profile_update, - }; -use commands::model::nostr_profile_relay::{ - model_nostr_profile_relay_set, model_nostr_profile_relay_unset, - }; -use commands::model::nostr_relay::{ - model_nostr_relay_create, model_nostr_relay_delete, model_nostr_relay_read, - model_nostr_relay_read_list, model_nostr_relay_update, - }; -use commands::model::trade_product::{ - model_trade_product_create, model_trade_product_delete, model_trade_product_read, - model_trade_product_read_list, model_trade_product_update, - }; -use commands::model::trade_product_location::{ - model_trade_product_location_set, model_trade_product_location_unset, - }; -use commands::model::trade_product_media::{ - model_trade_product_media_set, model_trade_product_media_unset, - }; -use radroots::Radroots; -use std::path::PathBuf; -use tauri::Manager; - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .plugin(tauri_plugin_shell::init()) - .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_fs::init()) - .plugin(tauri_plugin_geolocation::init()) - .plugin(tauri_plugin_http::init()) - .plugin(tauri_plugin_notification::init()) - .plugin(tauri_plugin_os::init()) - .plugin(tauri_plugin_store::Builder::new().build()) - .setup(|app| { - let data_dir = app - .handle() - .path() - .app_data_dir() - .expect("Failed to resolve app data dir"); - - let logs_dir = app.handle().path().app_log_dir().unwrap(); - - let fmt_data_dir = if cfg!(dev) { - PathBuf::from(format!("{}/dev", data_dir.to_string_lossy())) - } else { - PathBuf::from(format!("{}/release", data_dir.to_string_lossy())) - }; - - let fmt_logs_dir = if cfg!(dev) { - PathBuf::from(format!("{}/dev", logs_dir.to_string_lossy())) - } else { - PathBuf::from(format!("{}/release", logs_dir.to_string_lossy())) - }; - - tauri::async_runtime::block_on(async move { - let radroots = Radroots::new(fmt_data_dir, fmt_logs_dir).await; - app.manage(radroots); - }); - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - // %model% - model_location_gcs_create, - model_location_gcs_delete, - model_location_gcs_read, - model_location_gcs_read_list, - model_location_gcs_update, - model_log_error_create, - model_log_error_delete, - model_log_error_read, - model_log_error_read_list, - model_log_error_update, - model_media_image_create, - model_media_image_delete, - model_media_image_read, - model_media_image_read_list, - model_media_image_update, - model_nostr_profile_create, - model_nostr_profile_delete, - model_nostr_profile_read, - model_nostr_profile_read_list, - model_nostr_profile_relay_set, - model_nostr_profile_relay_unset, - model_nostr_profile_update, - model_nostr_relay_create, - model_nostr_relay_delete, - model_nostr_relay_read, - model_nostr_relay_read_list, - model_nostr_relay_update, - model_tables_reset, - model_trade_product_create, - model_trade_product_delete, - model_trade_product_location_set, - model_trade_product_location_unset, - model_trade_product_media_set, - model_trade_product_media_unset, - model_trade_product_read, - model_trade_product_read_list, - model_trade_product_update, - // %model% - keys_nostr_gen, - keys_nostr_add, - keys_nostr_read, - keys_nostr_read_all, - keys_nostr_delete, - keys_nostr_keystore_reset - ]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/crates/tauri/src/main.rs b/crates/tauri/src/main.rs @@ -1,6 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -fn main() { - radroots_lib::run(); -} diff --git a/crates/tauri/src/radroots.rs b/crates/tauri/src/radroots.rs @@ -1,24 +0,0 @@ -use std::path::PathBuf; - -use radroots_model::types::DatabaseConnection; - -use crate::util; - -pub struct Radroots { - pub db: DatabaseConnection, - pub data_dir: PathBuf, - pub logs_dir: PathBuf, -} - -impl Radroots { - pub async fn new(data_dir: PathBuf, logs_dir: PathBuf) -> Self { - util::init_keyring(&data_dir).await; - let db = util::init_db(&data_dir).await; - - Self { - db, - data_dir, - logs_dir, - } - } -} diff --git a/crates/tauri/tauri.conf.json b/crates/tauri/tauri.conf.json @@ -1,33 +0,0 @@ -{ - "$schema": "../../node_modules/@tauri-apps/cli/config.schema.json", - "identifier": "mobile.radroots.app", - "productName": "radroots", - "mainBinaryName": "radroots", - "build": { - "frontendDist": "../../app/build", - "devUrl": "http://localhost:21640", - "beforeDevCommand": "cd app && pnpm run dev:hmr", - "beforeBuildCommand": "cd app && pnpm run build" - }, - "app": { - "windows": [ - { - "title": "radroots", - "resizable": false, - "fullscreen": true, - "visible": true - } - ] - }, - "bundle": { - "active": false, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ] - } -} -\ No newline at end of file diff --git a/package.json b/package.json @@ -1,10 +1,10 @@ { - "name": "radroots", + "name": "tangle", "private": true, "license": "GPLv3", "scripts": { "build": "turbo build --filter=app", - "dev": "turbo dev", + "dev": "turbo dev --concurrency 11", "dev:ios": "pnpm run tauri ios dev 'iPhone 16'", "tauri": "tauri" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -332,6 +332,9 @@ importers: '@nostr-dev-kit/ndk': specifier: ^2.11.0 version: 2.11.0(typescript@5.7.3) + '@radroots/util': + specifier: workspace:* + version: link:../util nostr-geotags: specifier: workspace:* version: link:../nostr-geotags diff --git a/turbo.json b/turbo.json @@ -4,7 +4,9 @@ "globalEnv": [], "tasks": { "build": { - "env": [], + "env": [ + "RADROOTS_APP_PORT" + ], "dependsOn": [ "^build" ],