diff --git a/README.md b/README.md index ffea54a..238165f 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ Listing, reading, writing, creating directories, renaming and deleting are supported. Reads and writes stream in pieces of at most 1 MiB, so a file of any size moves without either side holding it whole. Conditional writes use `If-Match` and `If-None-Match`, which servers that return etags honour. Change -polling and publishing are not supported, and a rename never replaces an -existing target. +polling is not supported, and a rename never replaces an existing target. ## Building diff --git a/src/lib.rs b/src/lib.rs index ad50eae..8011633 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,13 +52,10 @@ fn transport(error: host::HostError) -> ErrorCode { } } -/// The path a locator names. This provider addresses by path only, because -/// WebDAV has no identity separate from the URL. -fn route(target: &Locator) -> Result { - match target { - Locator::Path(path) => Ok(path.clone()), - Locator::Id(_) => Err(ErrorCode::InvalidInput), - } +/// The path a locator names, the only way the contract addresses a resource. +fn route(target: &Locator) -> String { + let Locator::Path(path) = target; + path.clone() } fn session( @@ -143,7 +140,6 @@ fn info_of(found: &dav::Found) -> FileInfo { }, size: found.length, revision: found.etag.clone(), - id: None, } } @@ -194,7 +190,6 @@ impl GuestWriter for DavWriter { kind: EntryKind::File, size: 0, revision, - id: None, })) } } @@ -236,8 +231,6 @@ impl Guest for Webdav { // will refuse the header rather than silently overwrite. conditional_write: true, watch: false, - staged_write: false, - publishable: false, virtual_directories: false, }) } @@ -247,7 +240,7 @@ impl Guest for Webdav { } fn stat(target: Locator) -> Result { - let path = route(&target)?; + let path = route(&target); let body = exchange( host::Method::Propfind, &path, @@ -266,7 +259,7 @@ impl Guest for Webdav { cursor: Option, limit: u32, ) -> Result { - let path = route(&target)?; + let path = route(&target); let start: usize = match cursor { Some(value) => value.parse().map_err(|_| ErrorCode::InvalidInput)?, None => 0, @@ -296,7 +289,7 @@ impl Guest for Webdav { } fn open_read(target: Locator, offset: u64) -> Result { - let path = route(&target)?; + let path = route(&target); let call = begin( host::Method::Get, &path, @@ -320,7 +313,7 @@ impl Guest for Webdav { condition: WriteCondition, _size_hint: Option, ) -> Result { - let path = route(&target)?; + let path = route(&target); let guard = match condition { WriteCondition::CreateOnly => Some(host::Header { name: "if-none-match".to_owned(), @@ -340,13 +333,12 @@ impl Guest for Webdav { } fn mkdir(target: Locator) -> Result { - let path = route(&target)?; + let path = route(&target); exchange(host::Method::Mkcol, &path, Vec::new(), &[])?; Ok(FileInfo { kind: EntryKind::Directory, size: 0, revision: None, - id: None, }) } @@ -354,7 +346,7 @@ impl Guest for Webdav { target: Locator, destination: String, ) -> Result { - let path = route(&target)?; + let path = route(&target); let to = session(|session| Ok(dav::url(&session.root, &destination)))?; exchange( host::Method::Move, @@ -377,7 +369,7 @@ impl Guest for Webdav { } fn remove(target: Locator) -> Result<(), ErrorCode> { - let path = route(&target)?; + let path = route(&target); exchange(host::Method::Delete, &path, Vec::new(), &[])?; Ok(()) } @@ -385,10 +377,6 @@ impl Guest for Webdav { fn poll(_cursor: Option) -> Result { Err(ErrorCode::Unsupported) } - - fn publish() -> Result, ErrorCode> { - Err(ErrorCode::Unsupported) - } } sdk::export!(Webdav with_types_in sdk); diff --git a/wit/filesystem.wit b/wit/filesystem.wit index 560695e..4529372 100644 --- a/wit/filesystem.wit +++ b/wit/filesystem.wit @@ -74,9 +74,6 @@ interface host { variant setting { text(string), secret(string), toggle(bool) } /// Reads configuration or a session-only credential for this connection. config: func(key: string) -> option; - /// Reports that the current access token was rejected. The host refreshes - /// it once; a second rejection surfaces to the caller as denied. - invalidate-token: func(); /// Emits a diagnostic event. Never include secrets or private document data. log: func(level: log-level, message: string); @@ -101,36 +98,28 @@ interface provider { /// An opaque version token, at most 4096 UTF-8 bytes. type revision = string; - /// An opaque backend identity, at most 4096 UTF-8 bytes. The host never - /// parses, orders, or shows one, and never keeps one past the connection, - /// because a backend may reuse it. - type resource-id = string; - /// How one resource is named. A provider that hands out ids must accept - /// them back; one that does not may reject every id as invalid-input. - variant locator { path(string), id(resource-id) } + /// How one resource is named: a path within the connection root. + variant locator { path(string) } /// Optional operations. False capabilities must return unsupported. - /// Conditional-write promises atomic create-only and revision comparisons, - /// and cannot be combined with staged-write, where nothing to compare - /// exists until a publish lands. Virtual-directories says a directory is - /// only ever a prefix of something stored, as in a flat object store: the - /// host then never offers to create an empty one, warns that removing the - /// last child removes the folder, and does not call a vanished folder an - /// error. Such a provider may still accept mkdir by writing a marker, and - /// must answer unsupported when asked to rename a directory. + /// Conditional-write promises atomic create-only and revision comparisons. + /// Virtual-directories says a directory is only ever a prefix of something + /// stored, as in a flat object store: the host then never offers to create + /// an empty one, warns that removing the last child removes the folder, + /// and does not call a vanished folder an error. Such a provider may still + /// accept mkdir by writing a marker, and must answer unsupported when + /// asked to rename a directory. record capabilities { write: bool, mkdir: bool, rename: bool, remove: bool, conditional-write: bool, watch: bool, - staged-write: bool, publishable: bool, virtual-directories: bool, } - /// Byte length, an opaque revision, and a backend identity, each if known. + /// Byte length and an opaque revision, each if known. record file-info { kind: entry-kind, size: u64, revision: option, - id: option, } /// One child name, without slashes, dot segments, or control characters. record entry { name: string, info: file-info } @@ -198,10 +187,6 @@ interface provider { /// Polls for a bounded change page if the watch capability is present. No /// background callback or persistent subscription is installed by the host. poll: func(cursor: option) -> result; - /// Makes every staged write visible as one new root, if the publishable - /// capability is present, and names it, for example as a content - /// identifier. A none result means the publish needs another call. - publish: func() -> result, error-code>; } /// Memona filesystem extension ABI 0.1.0, distributed as a WebAssembly component.