feat: add webContents.getPrintersAsync() (#31023)

This deprecates the synchronous and blocking `webContents.getPrinters()`
function and introduces `webContents.getPrintersAsync()`, which is
asynchronous and non-blocking.

Signed-off-by: Darshan Sen <darshan.sen@postman.com>
This commit is contained in:
Darshan Sen 2021-10-25 23:46:58 +05:30 committed by GitHub
parent b936f5e14a
commit 8f51d3e1bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 4 deletions

View file

@ -1369,12 +1369,20 @@ Decrease the capturer count by one. The page will be set to hidden or occluded s
browser window is hidden or occluded and the capturer count reaches zero. If you want to browser window is hidden or occluded and the capturer count reaches zero. If you want to
decrease the hidden capturer count instead you should set `stayHidden` to true. decrease the hidden capturer count instead you should set `stayHidden` to true.
#### `contents.getPrinters()` #### `contents.getPrinters()` _Deprecated_
Get the system printer list. Get the system printer list.
Returns [`PrinterInfo[]`](structures/printer-info.md) Returns [`PrinterInfo[]`](structures/printer-info.md)
**Deprecated:** Should use the new [`contents.getPrintersAsync`](web-contents.md#contentsgetprintersasync) API.
#### `contents.getPrintersAsync()`
Get the system printer list.
Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/printer-info.md)
#### `contents.print([options], [callback])` #### `contents.print([options], [callback])`
* `options` Object (optional) * `options` Object (optional)

View file

@ -391,6 +391,17 @@ WebContents.prototype.getPrinters = function () {
} }
}; };
WebContents.prototype.getPrintersAsync = async function () {
// TODO(nornagon): this API has nothing to do with WebContents and should be
// moved.
if (printing.getPrinterListAsync) {
return printing.getPrinterListAsync();
} else {
console.error('Error: Printing feature is disabled.');
return [];
}
};
WebContents.prototype.loadFile = function (filePath, options = {}) { WebContents.prototype.loadFile = function (filePath, options = {}) {
if (typeof filePath !== 'string') { if (typeof filePath !== 'string') {
throw new Error('Must pass filePath as a string'); throw new Error('Must pass filePath as a string');

View file

@ -10,7 +10,11 @@
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "printing/backend/print_backend.h" #include "printing/backend/print_backend.h"
#include "shell/common/gin_helper/promise.h"
#include "shell/common/process_util.h"
#endif #endif
namespace gin { namespace gin {
@ -39,13 +43,16 @@ namespace electron {
namespace api { namespace api {
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
printing::PrinterList GetPrinterList() { printing::PrinterList GetPrinterList(v8::Isolate* isolate) {
EmitWarning(node::Environment::GetCurrent(isolate),
"Deprecation Warning: getPrinters() is deprecated. "
"Use the asynchronous and non-blocking version, "
"getPrintersAsync(), instead.",
"electron");
printing::PrinterList printers; printing::PrinterList printers;
auto print_backend = printing::PrintBackend::CreateInstance( auto print_backend = printing::PrintBackend::CreateInstance(
g_browser_process->GetApplicationLocale()); g_browser_process->GetApplicationLocale());
{ {
// TODO(deepak1556): Deprecate this api in favor of an
// async version and post a non blocing task call.
base::ThreadRestrictions::ScopedAllowIO allow_io; base::ThreadRestrictions::ScopedAllowIO allow_io;
printing::mojom::ResultCode code = printing::mojom::ResultCode code =
print_backend->EnumeratePrinters(&printers); print_backend->EnumeratePrinters(&printers);
@ -54,6 +61,32 @@ printing::PrinterList GetPrinterList() {
} }
return printers; return printers;
} }
v8::Local<v8::Promise> GetPrinterListAsync(v8::Isolate* isolate) {
gin_helper::Promise<printing::PrinterList> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce([]() {
printing::PrinterList printers;
auto print_backend = printing::PrintBackend::CreateInstance(
g_browser_process->GetApplicationLocale());
printing::mojom::ResultCode code =
print_backend->EnumeratePrinters(&printers);
if (code != printing::mojom::ResultCode::kSuccess)
LOG(INFO) << "Failed to enumerate printers";
return printers;
}),
base::BindOnce(
[](gin_helper::Promise<printing::PrinterList> promise,
const printing::PrinterList& printers) {
promise.Resolve(printers);
},
std::move(promise)));
return handle;
}
#endif #endif
} // namespace api } // namespace api
@ -64,6 +97,7 @@ namespace {
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
using electron::api::GetPrinterList; using electron::api::GetPrinterList;
using electron::api::GetPrinterListAsync;
#endif #endif
void Initialize(v8::Local<v8::Object> exports, void Initialize(v8::Local<v8::Object> exports,
@ -74,6 +108,8 @@ void Initialize(v8::Local<v8::Object> exports,
gin_helper::Dictionary dict(isolate, exports); gin_helper::Dictionary dict(isolate, exports);
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
dict.SetMethod("getPrinterList", base::BindRepeating(&GetPrinterList)); dict.SetMethod("getPrinterList", base::BindRepeating(&GetPrinterList));
dict.SetMethod("getPrinterListAsync",
base::BindRepeating(&GetPrinterListAsync));
#endif #endif
} }

View file

@ -1728,6 +1728,16 @@ describe('webContents module', () => {
}); });
}); });
ifdescribe(features.isPrintingEnabled())('getPrintersAsync()', () => {
afterEach(closeAllWindows);
it('can get printer list', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const printers = await w.webContents.getPrintersAsync();
expect(printers).to.be.an('array');
});
});
ifdescribe(features.isPrintingEnabled())('printToPDF()', () => { ifdescribe(features.isPrintingEnabled())('printToPDF()', () => {
let w: BrowserWindow; let w: BrowserWindow;

View file

@ -71,6 +71,7 @@ declare namespace Electron {
_printToPDF(options: any): Promise<Buffer>; _printToPDF(options: any): Promise<Buffer>;
_print(options: any, callback?: (success: boolean, failureReason: string) => void): void; _print(options: any, callback?: (success: boolean, failureReason: string) => void): void;
_getPrinters(): Electron.PrinterInfo[]; _getPrinters(): Electron.PrinterInfo[];
_getPrintersAsync(): Promise<Electron.PrinterInfo[]>;
_init(): void; _init(): void;
canGoToIndex(index: number): boolean; canGoToIndex(index: number): boolean;
getActiveIndex(): number; getActiveIndex(): number;