spacedrive/core/prisma/schema.prisma
Oscar Beaumont b015763a6f
More P2P docs (#2492)
* Remove relay

* restructure p2p

* wip

* cleanup webrtc

* split up P2P docs

* wip

* more wip

* the fork has moved

* finish local network discovery

* Document the relay system

* be less stupid

* a

* remote ip from deploy script

* remove debug from deploy script

* Explain relay setup and usage

* Physical pain

* fix

* error handling for relay setup

* Listeners Relay state + merge it into NLM state

* `node_remote_identity`

* redo libraries hook

* toggle relay active in settings

* Dedicated network settings page

* Stablise P2P debug page

* warning for rspc remote

* Linear links in docs

* fix p2p settings switches

* fix typescript errors on general page

* fix ipv6 listener status

* discovery method in UI

* Remove p2p debug menu on the sidebar

* wip

* lol

* wat

* fix

* another attempt at fixing library hook

* fix

* Remove sync from sidebar

* fix load library code

* I hate this

* Detect connections over the relay

* fix

* fixes

* a

* fix mDNS

* a bunch o fixes

* a bunch of state management fixes

* Metadata sync on connection

* skill issue

* fix markdown

* Clippy cleanup

* Backport #2380

* Update interface/locales/en/common.json

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/local-network-discovery.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/local-network-discovery.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p_proto.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/overview.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/overview.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/relay.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p_proto.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p_proto.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/transport-layer.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p_proto.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/local-network-discovery.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* Update docs/developers/p2p/sd_p2p_proto.mdx

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>

* a

* Cleaning binario section

* cleanup Docker message

* idk

* Idempotent listeners

* Manual peers working????

* minor fixes

* crazy idea - don't panic in the event loop

* fixes

* debug

* debug

* LAN badge in network settings

* Use `dns_lookup` instead of `tokio::net::lookup_host`

* fix

* bruh sandwich

* proper dialing

* a

* remove logs

* fix

* Small cleanup

* manual peers state on connected device

* a

* Fix manual discovery state + give it a badge

* Clippy improvements

* flip discovery priority

* Add `addrs` to debug query

* connection candidates in debug

* Fix state

* Clippppppppppppy

* Manual discovery badge

* Flesh out ping example

* Usage guide

* `sd_p2p_proto` examples

* More discovery docs

* More docs work

* docs docs docs and more docs

* PONG

* rename

---------

Co-authored-by: Matthew Yung <117509016+myung03@users.noreply.github.com>
2024-05-30 21:48:12 +08:00

690 lines
18 KiB
Plaintext

datasource db {
provider = "sqlite"
url = "file:dev.db"
}
generator client {
provider = "cargo prisma"
output = "../../crates/prisma/src/prisma"
module_path = "prisma"
client_format = "folder"
}
generator sync {
provider = "cargo prisma-sync"
output = "../../crates/prisma/src/prisma_sync"
client_format = "folder"
}
/// @local
model CRDTOperation {
id Int @id @default(autoincrement())
timestamp BigInt
model Int
record_id Bytes
// Enum: ??
kind String
data Bytes
instance_id Int
instance Instance @relation(fields: [instance_id], references: [id])
@@map("crdt_operation")
}
/// @local
model CloudCRDTOperation {
id Int @id @default(autoincrement())
timestamp BigInt
model Int
record_id Bytes
// Enum: ??
kind String
data Bytes
instance_id Int
instance Instance @relation(fields: [instance_id], references: [id])
@@map("cloud_crdt_operation")
}
/// @deprecated: This model has to exist solely for backwards compatibility.
/// @local
model Node {
id Int @id @default(autoincrement())
pub_id Bytes @unique
name String
// Enum: sd_core::node::Platform
platform Int
date_created DateTime
identity Bytes? // TODO: Change to required field in future
@@map("node")
}
// represents a single `.db` file (SQLite DB) that is paired to the current library.
// A `LibraryInstance` is always owned by a single `Node` but it's possible for that node to change (or two to be owned by a single node).
/// @local
model Instance {
id Int @id @default(autoincrement()) // This is is NOT globally unique
pub_id Bytes @unique // This UUID is meaningless and exists soley cause the `uhlc::ID` must be 16-bit. Really this should be derived from the `identity` field.
// Enum: sd_p2p::Identity (or sd_core::p2p::IdentityOrRemoteIdentity in early versions)
identity Bytes?
// Enum: sd_core::node::RemoteIdentity
remote_identity Bytes
// Enum: uuid::Uuid
node_id Bytes
// Enum: sd_core::node::RemoteIdentity
node_remote_identity Bytes? // TODO: This should not be optional
metadata Bytes? // TODO: This should not be optional
last_seen DateTime // Time core started for owner, last P2P message for P2P node
date_created DateTime
// clock timestamp for sync
timestamp BigInt?
locations Location[]
CRDTOperation CRDTOperation[]
CloudCRDTOperation CloudCRDTOperation[]
@@map("instance")
}
/// @local
model Statistics {
id Int @id @default(autoincrement())
date_captured DateTime @default(now())
total_object_count Int @default(0)
library_db_size String @default("0")
// local calulations
total_local_bytes_used String @default("0")
total_local_bytes_capacity String @default("0")
total_local_bytes_free String @default("0")
// library calculations
total_library_bytes String @default("0")
total_library_unique_bytes String @default("0")
total_library_preview_media_bytes String @default("0")
@@map("statistics")
}
/// @local
model Volume {
id Int @id @default(autoincrement())
name String
mount_point String
total_bytes_capacity String @default("0")
total_bytes_available String @default("0")
disk_type String?
filesystem String?
is_system Boolean @default(false)
date_modified DateTime @default(now())
@@unique([mount_point, name])
@@map("volume")
}
/// @shared(id: pub_id, modelId: 1)
model Location {
id Int @id @default(autoincrement())
pub_id Bytes @unique
name String?
path String?
total_capacity Int?
available_capacity Int?
size_in_bytes Bytes?
is_archived Boolean?
generate_preview_media Boolean?
sync_preview_media Boolean?
hidden Boolean?
date_created DateTime?
scan_state Int @default(0) // Enum: sd_core::location::ScanState
/// @local
// this is just a client side cache which is annoying but oh well (@brendan)
instance_id Int?
instance Instance? @relation(fields: [instance_id], references: [id], onDelete: SetNull)
file_paths FilePath[]
indexer_rules IndexerRulesInLocation[]
@@map("location")
}
/// @shared(id: pub_id, modelId: 2)
model FilePath {
id Int @id @default(autoincrement())
pub_id Bytes @unique
is_dir Boolean?
// content addressable storage id - blake3 sampled checksum
cas_id String?
// full byte contents digested into blake3 checksum
integrity_checksum String?
// location that owns this path
location_id Int?
location Location? @relation(fields: [location_id], references: [id], onDelete: SetNull)
// the path of the file relative to its location
materialized_path String?
// the name and extension, MUST have 'COLLATE NOCASE' in migration
name String?
extension String?
hidden Boolean?
size_in_bytes String? // deprecated
size_in_bytes_bytes Bytes?
inode Bytes? // This is actually an unsigned 64 bit integer, but we don't have this type in SQLite
// the unique Object for this file path
object_id Int?
object Object? @relation(fields: [object_id], references: [id], onDelete: SetNull)
key_id Int? // replacement for encryption
// permissions String?
date_created DateTime?
date_modified DateTime?
date_indexed DateTime?
// key Key? @relation(fields: [key_id], references: [id])
@@unique([location_id, materialized_path, name, extension])
@@unique([location_id, inode])
@@index([location_id])
@@index([location_id, materialized_path])
@@map("file_path")
}
/// @shared(id: pub_id, modelId: 3)
model Object {
id Int @id @default(autoincrement())
pub_id Bytes @unique
// Enum: sd_file_ext::kind::ObjectKind
kind Int?
key_id Int?
// handy ways to mark an object
hidden Boolean?
favorite Boolean?
important Boolean?
// if we have generated preview media for this object on at least one Node
// commented out for now by @brendonovich since they they're irrelevant to the sync system
// has_thumbnail Boolean?
// has_thumbstrip Boolean?
// has_video_preview Boolean?
// TODO: change above to:
// has_generated_thumbnail Boolean @default(false)
// has_generated_thumbstrip Boolean @default(false)
// has_generated_video_preview Boolean @default(false)
// integration with ipfs
// ipfs_id String?
// plain text note
note String?
// the original known creation date of this object
date_created DateTime?
date_accessed DateTime?
tags TagOnObject[]
labels LabelOnObject[]
albums ObjectInAlbum[]
spaces ObjectInSpace[]
file_paths FilePath[]
// comments Comment[]
exif_data ExifData?
ffmpeg_data FfmpegData?
// key Key? @relation(fields: [key_id], references: [id])
@@map("object")
}
// // keys allow us to know exactly which files can be decrypted with a given key
// // they can be "mounted" to a client, and then used to decrypt files automatically
// /// @shared(id: uuid)
// model Key {
// id Int @id @default(autoincrement())
// // uuid to identify the key
// uuid String @unique
// version String
// key_type String
// // the name that the user sets
// name String?
// // is this key the default for encryption?
// // was not tagged as unique as i'm not too sure if PCR will handle it
// // can always be tagged as unique, the keys API will need updating to use `find_unique()`
// default Boolean @default(false)
// // nullable if concealed for security
// date_created DateTime? @default(now())
// // encryption algorithm used to encrypt the key
// algorithm String
// // hashing algorithm used for hashing the key with the content salt
// hashing_algorithm String
// // salt used for encrypting data with this key
// content_salt Bytes
// // the *encrypted* master key (48 bytes)
// master_key Bytes
// // the nonce used for encrypting the master key
// master_key_nonce Bytes
// // the nonce used for encrypting the key
// key_nonce Bytes
// // the *encrypted* key
// key Bytes
// // the salt used for deriving the KEK (used for encrypting the master key) from the root key
// salt Bytes
// automount Boolean @default(false)
// objects Object[]
// file_paths FilePath[]
// @@map("key")
// }
/// @shared(id: object, modelId: 4)
model ExifData {
id Int @id @default(autoincrement())
resolution Bytes?
media_date Bytes?
media_location Bytes?
camera_data Bytes?
artist String?
description String?
copyright String?
exif_version String?
// purely for sorting/ordering, never sent to the frontend as they'd be useless
// these are also usually one-way, and not reversible
// (e.g. we can't get `MediaDate::Utc(2023-09-26T22:04:37+01:00)` from `1695758677` as we don't store the TZ)
epoch_time BigInt? // time since unix epoch
object_id Int @unique
object Object @relation(fields: [object_id], references: [id], onDelete: Cascade)
@@map("exif_data")
}
model FfmpegData {
id Int @id @default(autoincrement())
// Internal FFmpeg properties
formats String
bit_rate Bytes // Actually a i64 in the backend
duration Bytes? // Actually a i64 in the backend
start_time Bytes? // Actually a i64 in the backend
chapters FfmpegMediaChapter[]
programs FfmpegMediaProgram[]
// Metadata for search
title String?
creation_time DateTime?
date DateTime?
album_artist String?
disc String?
track String?
album String?
artist String?
metadata Bytes?
object Object @relation(fields: [object_id], references: [id], onDelete: Cascade)
object_id Int @unique
@@map("ffmpeg_data")
}
model FfmpegMediaChapter {
chapter_id Int
start Bytes // Actually a i64 in the backend
end Bytes // Actually a i64 in the backend
time_base_den Int
time_base_num Int
// Metadata for search
title String?
metadata Bytes?
ffmpeg_data FfmpegData @relation(fields: [ffmpeg_data_id], references: [id], onDelete: Cascade)
ffmpeg_data_id Int
@@id(name: "likeId", [ffmpeg_data_id, chapter_id])
@@map("ffmpeg_media_chapter")
}
model FfmpegMediaProgram {
program_id Int
streams FfmpegMediaStream[]
// Metadata for search
name String?
metadata Bytes?
ffmpeg_data FfmpegData @relation(fields: [ffmpeg_data_id], references: [id], onDelete: Cascade)
ffmpeg_data_id Int
@@id(name: "likeId", [ffmpeg_data_id, program_id])
@@map("ffmpeg_media_program")
}
model FfmpegMediaStream {
stream_id Int
name String?
codec FfmpegMediaCodec?
aspect_ratio_num Int
aspect_ratio_den Int
frames_per_second_num Int
frames_per_second_den Int
time_base_real_den Int
time_base_real_num Int
dispositions String?
// Metadata for search
title String?
encoder String?
language String?
duration Bytes? // Actually a i64 in the backend
metadata Bytes?
program FfmpegMediaProgram @relation(fields: [ffmpeg_data_id, program_id], references: [ffmpeg_data_id, program_id], onDelete: Cascade)
program_id Int
ffmpeg_data_id Int
@@id(name: "likeId", [ffmpeg_data_id, program_id, stream_id])
@@map("ffmpeg_media_stream")
}
model FfmpegMediaCodec {
id Int @id @default(autoincrement())
kind String?
sub_kind String?
tag String?
name String?
profile String?
bit_rate Int
video_props FfmpegMediaVideoProps?
audio_props FfmpegMediaAudioProps?
stream FfmpegMediaStream @relation(fields: [ffmpeg_data_id, program_id, stream_id], references: [ffmpeg_data_id, program_id, stream_id], onDelete: Cascade)
stream_id Int
program_id Int
ffmpeg_data_id Int
@@unique([ffmpeg_data_id, program_id, stream_id])
@@map("ffmpeg_media_codec")
}
model FfmpegMediaVideoProps {
id Int @id @default(autoincrement())
pixel_format String?
color_range String?
bits_per_channel Int?
color_space String?
color_primaries String?
color_transfer String?
field_order String?
chroma_location String?
width Int
height Int
aspect_ratio_num Int?
aspect_ratio_Den Int?
properties String?
codec FfmpegMediaCodec @relation(fields: [codec_id], references: [id], onDelete: Cascade)
codec_id Int @unique
@@map("ffmpeg_media_video_props")
}
model FfmpegMediaAudioProps {
id Int @id @default(autoincrement())
delay Int
padding Int
sample_rate Int?
sample_format String?
bit_per_sample Int?
channel_layout String?
codec FfmpegMediaCodec @relation(fields: [codec_id], references: [id], onDelete: Cascade)
codec_id Int @unique
@@map("ffmpeg_media_audio_props")
}
//// Tag ////
/// @shared(id: pub_id, modelId: 5)
model Tag {
id Int @id @default(autoincrement())
pub_id Bytes @unique
name String?
color String?
is_hidden Boolean? // user hidden entire tag
date_created DateTime?
date_modified DateTime?
tag_objects TagOnObject[]
@@map("tag")
}
/// @relation(item: object, group: tag, modelId: 6)
model TagOnObject {
object_id Int
object Object @relation(fields: [object_id], references: [id], onDelete: Restrict)
tag_id Int
tag Tag @relation(fields: [tag_id], references: [id], onDelete: Restrict)
date_created DateTime?
@@id([tag_id, object_id])
@@map("tag_on_object")
}
//// Label ////
/// @shared(id: name, modelId: 7)
model Label {
id Int @id @default(autoincrement())
name String @unique
date_created DateTime?
date_modified DateTime?
label_objects LabelOnObject[]
@@map("label")
}
/// @relation(item: object, group: label, modelId: 8)
model LabelOnObject {
date_created DateTime @default(now())
object_id Int
object Object @relation(fields: [object_id], references: [id], onDelete: Restrict)
label_id Int
label Label @relation(fields: [label_id], references: [id], onDelete: Restrict)
@@id([label_id, object_id])
@@map("label_on_object")
}
//// Space ////
model Space {
id Int @id @default(autoincrement())
pub_id Bytes @unique
name String?
description String?
date_created DateTime?
date_modified DateTime?
objects ObjectInSpace[]
@@map("space")
}
model ObjectInSpace {
space_id Int
space Space @relation(fields: [space_id], references: [id], onDelete: Restrict)
object_id Int
object Object @relation(fields: [object_id], references: [id], onDelete: Restrict)
@@id([space_id, object_id])
@@map("object_in_space")
}
//// Job ////
model Job {
id Bytes @id
name String?
action String? // Will be composed of "{action_description}(-{children_order})*"
// Enum: sd_core::job::job_manager:JobStatus
status Int? // 0 = Queued
// List of errors, separated by "\n\n" in case of failed jobs or completed with errors
errors_text String? // Deprecated, use `critical_error` or `non_critical_errors` instead
critical_error String? // Serialized error field with info about the failed job after completion
non_critical_errors Bytes? // Serialized non-critical errors field with info about the completed job with errors after completion
data Bytes? // Deprecated
metadata Bytes? // Serialized metadata field with info about the job after completion
parent_id Bytes?
task_count Int?
completed_task_count Int?
date_estimated_completion DateTime? // Estimated timestamp that the job will be complete at
date_created DateTime?
date_started DateTime? // Started execution
date_completed DateTime? // Finished execution
parent Job? @relation("jobs_dependency", fields: [parent_id], references: [id], onDelete: SetNull)
children Job[] @relation("jobs_dependency")
@@map("job")
}
//// Album ////
model Album {
id Int @id
pub_id Bytes @unique
name String?
is_hidden Boolean?
date_created DateTime?
date_modified DateTime?
objects ObjectInAlbum[]
@@map("album")
}
model ObjectInAlbum {
date_created DateTime?
album_id Int
album Album @relation(fields: [album_id], references: [id], onDelete: NoAction)
object_id Int
object Object @relation(fields: [object_id], references: [id], onDelete: NoAction)
@@id([album_id, object_id])
@@map("object_in_album")
}
//// Indexer Rules ////
model IndexerRule {
id Int @id @default(autoincrement())
pub_id Bytes @unique
name String? @unique
default Boolean?
rules_per_kind Bytes?
date_created DateTime?
date_modified DateTime?
locations IndexerRulesInLocation[]
@@map("indexer_rule")
}
model IndexerRulesInLocation {
location_id Int
location Location @relation(fields: [location_id], references: [id], onDelete: Restrict)
indexer_rule_id Int
indexer_rule IndexerRule @relation(fields: [indexer_rule_id], references: [id], onDelete: Restrict)
@@id([location_id, indexer_rule_id])
@@map("indexer_rule_in_location")
}
/// @shared(id: key, modelId: 9)
model Preference {
key String @id
value Bytes?
@@map("preference")
}
model Notification {
id Int @id @default(autoincrement())
read Boolean @default(false)
// Enum: crate::api::notifications::NotificationData
data Bytes
expires_at DateTime?
@@map("notification")
}
/// @shared(id: pub_id, modelId: 10)
model SavedSearch {
id Int @id @default(autoincrement())
pub_id Bytes @unique
// enum: crate::api::search::saved::SearchTarget
target String?
search String?
filters String?
name String?
icon String?
description String?
// order Int? // Add this line to include ordering
date_created DateTime?
date_modified DateTime?
@@map("saved_search")
}