diff --git a/src/lib/fixes.ts b/src/lib/fixes.ts index 8cdb23c..a5acd21 100644 --- a/src/lib/fixes.ts +++ b/src/lib/fixes.ts @@ -18,15 +18,64 @@ // GNU General Public License for more details. import type GLib from "gi://GLib"; +import type Gio from "gi://Gio"; +import type Soup from "gi://Soup"; /** * This module provides workarounds and fixes for various incomplete type * declarations in Gnome shell types and its dependencies. */ +type Promisified = AsyncFN extends ( + ...args: infer Args +) => void + ? FinishFN extends (result: Gio.AsyncResult) => infer TReturn + ? (...args: Args) => Promise + : never + : never; + /** * @see https://github.com/gjsify/ts-for-gir/issues/196 */ export interface GLibErrorWithStack extends GLib.Error { readonly stack: string; } + +/** + * @see https://github.com/gjsify/ts-for-gir/issues/171#issuecomment-2117301067 + */ +export interface PromisifiedFileOutputStream extends Gio.FileOutputStream { + splice_async: Promisified< + Gio.OutputStream["splice_async"], + Gio.OutputStream["splice_finish"] + >; +} + +/** + * @see https://github.com/gjsify/ts-for-gir/issues/171#issuecomment-2117301067 + */ +export interface PromisifiedGioFile extends Gio.File { + create_async: Promisified< + Gio.File["create_async"], + Gio.File["create_finish"] + >; + delete_async: Promisified< + Gio.File["delete_async"], + Gio.File["delete_finish"] + >; +} + +/** + * @see https://github.com/gjsify/ts-for-gir/issues/171#issuecomment-2117301067 + */ +export interface PromisifiedSoupSession extends Soup.Session { + send_async: Promisified< + Soup.Session["send_async"], + Soup.Session["send_finish"] + >; + + send_and_read_async: Promisified< + Soup.Session["send_and_read_async"], + Soup.Session["send_and_read_finish"] + >; +} diff --git a/src/lib/network/http.ts b/src/lib/network/http.ts index 2325eed..bd2abba 100644 --- a/src/lib/network/http.ts +++ b/src/lib/network/http.ts @@ -23,6 +23,11 @@ import Soup from "gi://Soup"; import { IOError } from "../common/gio.js"; import type { ExtensionMetadata } from "resource:///org/gnome/shell/extensions/extension.js"; +import { + PromisifiedFileOutputStream, + PromisifiedGioFile, + PromisifiedSoupSession, +} from "../fixes.js"; export const createSession = ( extensionMetadata: ExtensionMetadata, @@ -83,7 +88,7 @@ export const getString = async ( cancellable: Gio.Cancellable, ): Promise => { const message = Soup.Message.new("GET", url); - const response = await session + const response = await (session as PromisifiedSoupSession) .send_and_read_async(message, 0, cancellable) .catch((cause: unknown) => { throw new HttpRequestError(url, `Failed to get data from ${url}`, { @@ -146,7 +151,7 @@ const deletePartialDownloadIgnoreError = async ( cancellable: Gio.Cancellable | null, ): Promise => { try { - await file.delete_async(0, cancellable); + await (file as PromisifiedGioFile).delete_async(0, cancellable); } catch (error) { console.warn( `Failed to delete result of partial download at ${file.get_path() ?? ""}`, @@ -173,7 +178,7 @@ export const downloadToFile = async ( return; } const message = Soup.Message.new("GET", url); - const source = await session + const source = await (session as PromisifiedSoupSession) .send_async(message, 0, cancellable) .catch((cause: unknown) => { throw new HttpRequestError(url, `Failed to make GET request to ${url}`, { @@ -215,7 +220,7 @@ export const downloadToFile = async ( } // Now open the target file for reading, and safely delete it in case of error. try { - const sink = await target + const sink = await (target as PromisifiedGioFile) .create_async(Gio.FileCreateFlags.NONE, 0, null) .catch((cause: unknown) => { throw new IOError( @@ -223,7 +228,7 @@ export const downloadToFile = async ( { cause }, ); }); - await sink + await (sink as PromisifiedFileOutputStream) .splice_async( source, Gio.OutputStreamSpliceFlags.CLOSE_SOURCE |