@esslassi/electron-printer 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/print.cpp CHANGED
@@ -1,272 +1,353 @@
1
- #include <napi.h>
2
- #include "printer_factory.h"
3
-
4
- class PrinterWorker : public Napi::AsyncWorker
5
- {
6
- private:
7
- std::unique_ptr<PrinterInterface> printer;
8
- std::function<void(PrinterWorker *)> work;
9
- PrinterInfo printerResult;
10
- std::vector<PrinterInfo> printersResult;
11
- bool isMultiplePrinters;
12
- bool success;
13
-
14
- public:
15
- PrinterWorker(Napi::Function &callback, std::function<void(PrinterWorker *)> executeWork)
16
- : Napi::AsyncWorker(callback),
17
- work(executeWork),
18
- isMultiplePrinters(false),
19
- success(false)
20
- {
21
- printer = PrinterFactory::Create();
22
- }
23
-
24
- void Execute() override
25
- {
26
- if (printer)
27
- {
28
- work(this);
29
- }
30
- else
31
- {
32
- SetError("Failed to create printer");
33
- }
34
- }
35
-
36
- void OnOK() override
37
- {
38
- Napi::Env env = Env();
39
- Napi::HandleScope scope(env);
40
-
41
- if (isMultiplePrinters)
42
- {
43
- Napi::Array result = Napi::Array::New(env, printersResult.size());
44
- for (size_t i = 0; i < printersResult.size(); i++)
45
- {
46
- result.Set(i, CreatePrinterObject(env, printersResult[i]));
47
- }
48
- Callback().Call({env.Null(), result});
49
- }
50
- else
51
- {
52
- Callback().Call({env.Null(), CreatePrinterObject(env, printerResult)});
53
- }
54
- }
55
-
56
- PrinterInterface *GetPrinter() { return printer.get(); }
57
- void SetPrinterResult(const PrinterInfo &result) { printerResult = result; }
58
- void SetPrintersResult(const std::vector<PrinterInfo> &result)
59
- {
60
- printersResult = result;
61
- isMultiplePrinters = true;
62
- }
63
- void SetSuccess(bool value) { success = value; }
64
- bool GetSuccess() const { return success; }
65
-
66
- private:
67
- Napi::Object CreatePrinterObject(Napi::Env env, const PrinterInfo &printer)
68
- {
69
- Napi::Object result = Napi::Object::New(env);
70
- result.Set("name", printer.name);
71
- result.Set("status", printer.status);
72
-
73
- // incluir estes campos se NÃO for um resultado do PrintDirect
74
- if (!success)
75
- { // Se success for true, é um PrintDirect
76
- result.Set("isDefault", printer.isDefault);
77
-
78
- Napi::Object details = Napi::Object::New(env);
79
- for (const auto &detail : printer.details)
80
- {
81
- details.Set(detail.first, detail.second);
82
- }
83
- result.Set("details", details);
84
- }
85
-
86
- return result;
87
- }
88
- };
89
-
90
- Napi::Value PrintDirect(const Napi::CallbackInfo &info)
91
- {
92
- Napi::Env env = info.Env();
93
-
94
- if (info.Length() < 1 || !info[0].IsObject())
95
- {
96
- Napi::TypeError::New(env, "Expected an object as argument").ThrowAsJavaScriptException();
97
- return env.Null();
98
- }
99
-
100
- Napi::Object options = info[0].As<Napi::Object>();
101
-
102
- if (!options.Has("printerName") || !options.Has("data"))
103
- {
104
- Napi::TypeError::New(env, "Object must have 'printerName' and 'data' properties").ThrowAsJavaScriptException();
105
- return env.Null();
106
- }
107
-
108
- if (!options.Get("printerName").IsString())
109
- {
110
- Napi::TypeError::New(env, "printerName must be a string").ThrowAsJavaScriptException();
111
- return env.Null();
112
- }
113
-
114
- Napi::Value data = options.Get("data");
115
- if (!data.IsString() && !data.IsBuffer())
116
- {
117
- Napi::TypeError::New(env, "data must be a string or Buffer").ThrowAsJavaScriptException();
118
- return env.Null();
119
- }
120
-
121
- std::string printerName = options.Get("printerName").As<Napi::String>().Utf8Value();
122
- std::vector<uint8_t> printData;
123
-
124
- if (data.IsString())
125
- {
126
- std::string strData = data.As<Napi::String>().Utf8Value();
127
- printData.assign(strData.begin(), strData.end());
128
- }
129
- else
130
- {
131
- Napi::Buffer<uint8_t> buffer = data.As<Napi::Buffer<uint8_t>>();
132
- printData.assign(buffer.Data(), buffer.Data() + buffer.Length());
133
- }
134
-
135
- std::string dataType = "RAW";
136
- if (options.Has("dataType") && options.Get("dataType").IsString())
137
- {
138
- dataType = options.Get("dataType").As<Napi::String>().Utf8Value();
139
- }
140
-
141
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
142
-
143
- auto callback = Napi::Function::New(env, [deferred](const Napi::CallbackInfo &info)
144
- {
145
- if (info[0].IsNull()) {
146
- deferred.Resolve(info[1]);
147
- } else {
148
- deferred.Reject(info[0].As<Napi::Error>().Value());
149
- }
150
- return info.Env().Undefined(); });
151
-
152
- auto worker = new PrinterWorker(
153
- callback,
154
- [printerName, printData, dataType](PrinterWorker *worker)
155
- {
156
- bool success = worker->GetPrinter()->PrintDirect(printerName, printData, dataType);
157
- worker->SetSuccess(true); // Indica que é um resultado do PrintDirect
158
- PrinterInfo result;
159
- result.name = printerName;
160
- result.status = success ? "success" : "failed";
161
- worker->SetPrinterResult(result);
162
- });
163
-
164
- worker->Queue();
165
- return deferred.Promise();
166
- }
167
-
168
- Napi::Value GetPrinters(const Napi::CallbackInfo &info)
169
- {
170
- Napi::Env env = info.Env();
171
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
172
-
173
- auto callback = Napi::Function::New(env, [deferred](const Napi::CallbackInfo &info)
174
- {
175
- if (info[0].IsNull()) {
176
- deferred.Resolve(info[1]);
177
- } else {
178
- deferred.Reject(info[0].As<Napi::Error>().Value());
179
- }
180
- return info.Env().Undefined(); });
181
-
182
- auto worker = new PrinterWorker(
183
- callback,
184
- [](PrinterWorker *worker)
185
- {
186
- auto printers = worker->GetPrinter()->GetPrinters();
187
- worker->SetPrintersResult(printers);
188
- });
189
-
190
- worker->Queue();
191
- return deferred.Promise();
192
- }
193
-
194
- Napi::Value GetSystemDefaultPrinter(const Napi::CallbackInfo &info)
195
- {
196
- Napi::Env env = info.Env();
197
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
198
-
199
- auto callback = Napi::Function::New(env, [deferred](const Napi::CallbackInfo &info)
200
- {
201
- if (info[0].IsNull()) {
202
- deferred.Resolve(info[1]);
203
- } else {
204
- deferred.Reject(info[0].As<Napi::Error>().Value());
205
- }
206
- return info.Env().Undefined(); });
207
-
208
- auto worker = new PrinterWorker(
209
- callback,
210
- [](PrinterWorker *worker)
211
- {
212
- auto printer = worker->GetPrinter()->GetSystemDefaultPrinter();
213
- worker->SetPrinterResult(printer);
214
- });
215
-
216
- worker->Queue();
217
- return deferred.Promise();
218
- }
219
-
220
- Napi::Value GetStatusPrinter(const Napi::CallbackInfo &info)
221
- {
222
- Napi::Env env = info.Env();
223
-
224
- if (info.Length() < 1 || !info[0].IsObject())
225
- {
226
- Napi::TypeError::New(env, "Expected an object as argument").ThrowAsJavaScriptException();
227
- return env.Null();
228
- }
229
-
230
- Napi::Object options = info[0].As<Napi::Object>();
231
-
232
- Napi::Array propertyNames = options.GetPropertyNames();
233
- for (uint32_t i = 0; i < propertyNames.Length(); i++)
234
- {
235
- propertyNames.Get(i).As<Napi::String>();
236
- }
237
-
238
- if (!options.Has("printerName"))
239
- {
240
- Napi::TypeError::New(env, "Object must have 'printerName' property").ThrowAsJavaScriptException();
241
- return env.Null();
242
- }
243
-
244
- if (!options.Get("printerName").IsString())
245
- {
246
- Napi::TypeError::New(env, "printerName must be a string").ThrowAsJavaScriptException();
247
- return env.Null();
248
- }
249
-
250
- std::string printerName = options.Get("printerName").As<Napi::String>().Utf8Value();
251
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
252
-
253
- auto callback = Napi::Function::New(env, [deferred](const Napi::CallbackInfo &info)
254
- {
255
- if (info[0].IsNull()) {
256
- deferred.Resolve(info[1]);
257
- } else {
258
- deferred.Reject(info[0].As<Napi::Error>().Value());
259
- }
260
- return info.Env().Undefined(); });
261
-
262
- auto worker = new PrinterWorker(
263
- callback,
264
- [printerName](PrinterWorker *worker)
265
- {
266
- auto printer = worker->GetPrinter()->GetStatusPrinter(printerName);
267
- worker->SetPrinterResult(printer);
268
- });
269
-
270
- worker->Queue();
271
- return deferred.Promise();
272
- }
1
+ #include <napi.h>
2
+ #include <fstream>
3
+ #include <vector>
4
+ #include <memory>
5
+ #include <functional>
6
+
7
+ #include "printer_factory.h"
8
+ #include "printer_interface.h"
9
+
10
+ static std::unique_ptr<PrinterInterface> P()
11
+ {
12
+ return PrinterFactory::Create();
13
+ }
14
+
15
+ /* =========================================================
16
+ JS Converters
17
+ ========================================================= */
18
+
19
+ static Napi::Object JsPrinterDetails(Napi::Env env, const PrinterDetailsNative &p)
20
+ {
21
+ Napi::Object o = Napi::Object::New(env);
22
+ o.Set("name", p.name);
23
+ o.Set("isDefault", p.isDefault);
24
+
25
+ Napi::Object opts = Napi::Object::New(env);
26
+ for (auto &kv : p.options)
27
+ opts.Set(kv.first, kv.second);
28
+
29
+ o.Set("options", opts);
30
+ return o;
31
+ }
32
+
33
+ static Napi::Object JsDriverOptions(Napi::Env env, const DriverOptions &opts)
34
+ {
35
+ Napi::Object out = Napi::Object::New(env);
36
+ for (auto &group : opts)
37
+ {
38
+ Napi::Object choices = Napi::Object::New(env);
39
+ for (auto &choice : group.second)
40
+ choices.Set(choice.first, Napi::Boolean::New(env, choice.second));
41
+ out.Set(group.first, choices);
42
+ }
43
+ return out;
44
+ }
45
+
46
+ static Napi::Object JsJobDetails(Napi::Env env, const JobDetailsNative &j)
47
+ {
48
+ Napi::Object o = Napi::Object::New(env);
49
+ o.Set("id", j.id);
50
+ o.Set("name", j.name);
51
+ o.Set("printerName", j.printerName);
52
+ o.Set("user", j.user);
53
+ o.Set("format", j.format);
54
+ o.Set("priority", j.priority);
55
+ o.Set("size", j.size);
56
+
57
+ Napi::Array st = Napi::Array::New(env, j.status.size());
58
+ for (size_t i = 0; i < j.status.size(); i++)
59
+ st.Set((uint32_t)i, j.status[i]);
60
+ o.Set("status", st);
61
+
62
+ o.Set("completedTime", Napi::Date::New(env, (double)j.completedTime * 1000.0));
63
+ o.Set("creationTime", Napi::Date::New(env, (double)j.creationTime * 1000.0));
64
+ o.Set("processingTime", Napi::Date::New(env, (double)j.processingTime * 1000.0));
65
+
66
+ return o;
67
+ }
68
+
69
+ /* =========================================================
70
+ Sync Methods
71
+ ========================================================= */
72
+
73
+ Napi::Value getPrinters(const Napi::CallbackInfo &info)
74
+ {
75
+ auto env = info.Env();
76
+ auto printer = P();
77
+ auto list = printer->GetPrinters();
78
+
79
+ Napi::Array arr = Napi::Array::New(env, list.size());
80
+ for (size_t i = 0; i < list.size(); i++)
81
+ arr.Set((uint32_t)i, JsPrinterDetails(env, list[i]));
82
+
83
+ return arr;
84
+ }
85
+
86
+ Napi::Value getPrinter(const Napi::CallbackInfo &info)
87
+ {
88
+ auto env = info.Env();
89
+ if (info.Length() < 1 || !info[0].IsString())
90
+ Napi::TypeError::New(env, "printerName required").ThrowAsJavaScriptException();
91
+
92
+ auto printer = P();
93
+ auto p = printer->GetPrinter(info[0].As<Napi::String>().Utf8Value());
94
+ return JsPrinterDetails(env, p);
95
+ }
96
+
97
+ Napi::Value getPrinterDriverOptions(const Napi::CallbackInfo &info)
98
+ {
99
+ auto env = info.Env();
100
+ if (info.Length() < 1 || !info[0].IsString())
101
+ Napi::TypeError::New(env, "printerName required").ThrowAsJavaScriptException();
102
+
103
+ auto printer = P();
104
+ auto opts = printer->GetPrinterDriverOptions(info[0].As<Napi::String>().Utf8Value());
105
+ return JsDriverOptions(env, opts);
106
+ }
107
+
108
+ Napi::Value getSelectedPaperSize(const Napi::CallbackInfo &info)
109
+ {
110
+ auto env = info.Env();
111
+ if (info.Length() < 1 || !info[0].IsString())
112
+ Napi::TypeError::New(env, "printerName required").ThrowAsJavaScriptException();
113
+
114
+ auto printer = P();
115
+ auto ps = printer->GetSelectedPaperSize(info[0].As<Napi::String>().Utf8Value());
116
+ return Napi::String::New(env, ps);
117
+ }
118
+
119
+ Napi::Value getDefaultPrinterName(const Napi::CallbackInfo &info)
120
+ {
121
+ auto env = info.Env();
122
+ auto printer = P();
123
+ auto name = printer->GetDefaultPrinterName();
124
+ if (name.empty())
125
+ return env.Undefined();
126
+ return Napi::String::New(env, name);
127
+ }
128
+
129
+ Napi::Value getSupportedPrintFormats(const Napi::CallbackInfo &info)
130
+ {
131
+ auto env = info.Env();
132
+ auto printer = P();
133
+ auto formats = printer->GetSupportedPrintFormats();
134
+
135
+ Napi::Array arr = Napi::Array::New(env, formats.size());
136
+ for (size_t i = 0; i < formats.size(); i++)
137
+ arr.Set((uint32_t)i, formats[i]);
138
+
139
+ return arr;
140
+ }
141
+
142
+ Napi::Value getSupportedJobCommands(const Napi::CallbackInfo &info)
143
+ {
144
+ auto env = info.Env();
145
+ auto printer = P();
146
+ auto cmds = printer->GetSupportedJobCommands();
147
+
148
+ Napi::Array arr = Napi::Array::New(env, cmds.size());
149
+ for (size_t i = 0; i < cmds.size(); i++)
150
+ arr.Set((uint32_t)i, cmds[i]);
151
+
152
+ return arr;
153
+ }
154
+
155
+ Napi::Value getJob(const Napi::CallbackInfo &info)
156
+ {
157
+ auto env = info.Env();
158
+ if (info.Length() < 2 || !info[0].IsString() || !info[1].IsNumber())
159
+ Napi::TypeError::New(env, "getJob(printerName, jobId)").ThrowAsJavaScriptException();
160
+
161
+ auto printer = P();
162
+ auto job = printer->GetJob(
163
+ info[0].As<Napi::String>().Utf8Value(),
164
+ info[1].As<Napi::Number>().Int32Value());
165
+
166
+ return JsJobDetails(env, job);
167
+ }
168
+
169
+ Napi::Value setJob(const Napi::CallbackInfo &info)
170
+ {
171
+ auto env = info.Env();
172
+ if (info.Length() < 3 || !info[0].IsString() || !info[1].IsNumber() || !info[2].IsString())
173
+ Napi::TypeError::New(env, "setJob(printerName, jobId, command)").ThrowAsJavaScriptException();
174
+
175
+ auto printer = P();
176
+ printer->SetJob(
177
+ info[0].As<Napi::String>().Utf8Value(),
178
+ info[1].As<Napi::Number>().Int32Value(),
179
+ info[2].As<Napi::String>().Utf8Value());
180
+
181
+ return env.Undefined();
182
+ }
183
+
184
+ /* =========================================================
185
+ Async Print Worker
186
+ ========================================================= */
187
+
188
+ class PrintWorker : public Napi::AsyncWorker
189
+ {
190
+ public:
191
+ PrintWorker(
192
+ Napi::Function successCb,
193
+ Napi::Function errorCb,
194
+ std::function<int()> workFn)
195
+ : Napi::AsyncWorker(successCb),
196
+ successRef(Napi::Persistent(successCb)),
197
+ errorRef(Napi::Persistent(errorCb)),
198
+ work(workFn)
199
+ {}
200
+
201
+ void Execute() override
202
+ {
203
+ try
204
+ {
205
+ jobId = work();
206
+ if (jobId <= 0)
207
+ SetError("Print failed");
208
+ }
209
+ catch (...)
210
+ {
211
+ SetError("Print failed (exception)");
212
+ }
213
+ }
214
+
215
+ void OnOK() override
216
+ {
217
+ Napi::HandleScope scope(Env());
218
+ successRef.Call({ Napi::String::New(Env(), std::to_string(jobId)) });
219
+ }
220
+
221
+ void OnError(const Napi::Error &e) override
222
+ {
223
+ Napi::HandleScope scope(Env());
224
+ errorRef.Call({ e.Value() });
225
+ }
226
+
227
+ private:
228
+ Napi::FunctionReference successRef;
229
+ Napi::FunctionReference errorRef;
230
+ std::function<int()> work;
231
+ int jobId = 0;
232
+ };
233
+
234
+ static Napi::Function SafeCb(Napi::Env env, Napi::Object opt, const char *key)
235
+ {
236
+ if (opt.Has(key) && opt.Get(key).IsFunction())
237
+ return opt.Get(key).As<Napi::Function>();
238
+
239
+ return Napi::Function::New(env, [](const Napi::CallbackInfo &) {});
240
+ }
241
+
242
+ /* =========================================================
243
+ printDirect
244
+ ========================================================= */
245
+
246
+ Napi::Value printDirect(const Napi::CallbackInfo &info)
247
+ {
248
+ auto env = info.Env();
249
+
250
+ if (info.Length() < 1 || !info[0].IsObject())
251
+ Napi::TypeError::New(env, "options object required").ThrowAsJavaScriptException();
252
+
253
+ Napi::Object opt = info[0].As<Napi::Object>();
254
+
255
+ if (!opt.Has("data"))
256
+ Napi::TypeError::New(env, "options.data required").ThrowAsJavaScriptException();
257
+
258
+ std::string printerName;
259
+ if (opt.Has("printer") && opt.Get("printer").IsString())
260
+ printerName = opt.Get("printer").As<Napi::String>().Utf8Value();
261
+
262
+ std::string type = "RAW";
263
+ if (opt.Has("type") && opt.Get("type").IsString())
264
+ type = opt.Get("type").As<Napi::String>().Utf8Value();
265
+
266
+ StringMap driverOpts;
267
+ if (opt.Has("options") && opt.Get("options").IsObject())
268
+ {
269
+ Napi::Object o = opt.Get("options").As<Napi::Object>();
270
+ auto props = o.GetPropertyNames();
271
+ for (uint32_t i = 0; i < props.Length(); i++)
272
+ {
273
+ auto k = props.Get(i).As<Napi::String>().Utf8Value();
274
+ auto v = o.Get(k).ToString().Utf8Value();
275
+ driverOpts[k] = v;
276
+ }
277
+ }
278
+
279
+ std::vector<uint8_t> data;
280
+ auto d = opt.Get("data");
281
+
282
+ if (d.IsBuffer())
283
+ {
284
+ auto b = d.As<Napi::Buffer<uint8_t>>();
285
+ data.assign(b.Data(), b.Data() + b.Length());
286
+ }
287
+ else
288
+ {
289
+ auto s = d.ToString().Utf8Value();
290
+ data.assign(s.begin(), s.end());
291
+ }
292
+
293
+ auto successCb = SafeCb(env, opt, "success");
294
+ auto errorCb = SafeCb(env, opt, "error");
295
+
296
+ auto worker = new PrintWorker(
297
+ successCb,
298
+ errorCb,
299
+ [printerName, data, type, driverOpts]() -> int
300
+ {
301
+ auto printer = P();
302
+ std::string usePrinter = printerName.empty()
303
+ ? printer->GetDefaultPrinterName()
304
+ : printerName;
305
+
306
+ return printer->PrintDirect(usePrinter, data, type, driverOpts);
307
+ });
308
+
309
+ worker->Queue();
310
+ return env.Undefined();
311
+ }
312
+
313
+ /* =========================================================
314
+ printFile
315
+ ========================================================= */
316
+
317
+ Napi::Value printFile(const Napi::CallbackInfo &info)
318
+ {
319
+ auto env = info.Env();
320
+
321
+ if (info.Length() < 1 || !info[0].IsObject())
322
+ Napi::TypeError::New(env, "options object required").ThrowAsJavaScriptException();
323
+
324
+ Napi::Object opt = info[0].As<Napi::Object>();
325
+
326
+ if (!opt.Has("filename") || !opt.Get("filename").IsString())
327
+ Napi::TypeError::New(env, "options.filename required").ThrowAsJavaScriptException();
328
+
329
+ std::string filename = opt.Get("filename").As<Napi::String>().Utf8Value();
330
+
331
+ std::string printerName;
332
+ if (opt.Has("printer") && opt.Get("printer").IsString())
333
+ printerName = opt.Get("printer").As<Napi::String>().Utf8Value();
334
+
335
+ auto successCb = SafeCb(env, opt, "success");
336
+ auto errorCb = SafeCb(env, opt, "error");
337
+
338
+ auto worker = new PrintWorker(
339
+ successCb,
340
+ errorCb,
341
+ [printerName, filename]() -> int
342
+ {
343
+ auto printer = P();
344
+ std::string usePrinter = printerName.empty()
345
+ ? printer->GetDefaultPrinterName()
346
+ : printerName;
347
+
348
+ return printer->PrintFile(usePrinter, filename);
349
+ });
350
+
351
+ worker->Queue();
352
+ return env.Undefined();
353
+ }