@esslassi/electron-printer 0.0.3 → 0.0.5

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.
@@ -0,0 +1,166 @@
1
+ #include "mac_printer.h"
2
+ #include <cups/cups.h>
3
+
4
+ std::string MacPrinter::GetPrinterStatus(ipp_pstate_t state)
5
+ {
6
+ switch (state)
7
+ {
8
+ case IPP_PRINTER_IDLE:
9
+ return "ready";
10
+ case IPP_PRINTER_PROCESSING:
11
+ return "printing";
12
+ case IPP_PRINTER_STOPPED:
13
+ return "stopped";
14
+ default:
15
+ return "unknown";
16
+ }
17
+ }
18
+
19
+ PrinterInfo MacPrinter::GetPrinterDetails(const std::string &printerName, bool isDefault)
20
+ {
21
+ PrinterInfo info;
22
+ info.name = printerName;
23
+ info.isDefault = isDefault;
24
+
25
+ cups_dest_t *dests;
26
+ int num_dests = cupsGetDests(&dests);
27
+ cups_dest_t *dest = cupsGetDest(printerName.c_str(), NULL, num_dests, dests);
28
+
29
+ if (dest != NULL)
30
+ {
31
+ for (int i = 0; i < dest->num_options; i++)
32
+ {
33
+ info.details[dest->options[i].name] = dest->options[i].value;
34
+ }
35
+
36
+ http_t *http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
37
+ HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
38
+ if (http != NULL)
39
+ {
40
+ ipp_t *request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
41
+
42
+ char uri[HTTP_MAX_URI];
43
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
44
+ "localhost", 0, "/printers/%s", printerName.c_str());
45
+
46
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
47
+ "printer-uri", NULL, uri);
48
+
49
+ ipp_t *response = cupsDoRequest(http, request, "/");
50
+ if (response != NULL)
51
+ {
52
+ ipp_attribute_t *attr = ippFindAttribute(response,
53
+ "printer-state", IPP_TAG_ENUM);
54
+ if (attr != NULL)
55
+ {
56
+ info.status = GetPrinterStatus((ipp_pstate_t)ippGetInteger(attr, 0));
57
+ }
58
+
59
+ attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT);
60
+ if (attr != NULL)
61
+ info.details["location"] = ippGetString(attr, 0, NULL);
62
+
63
+ attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT);
64
+ if (attr != NULL)
65
+ info.details["comment"] = ippGetString(attr, 0, NULL);
66
+
67
+ attr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT);
68
+ if (attr != NULL)
69
+ info.details["driver"] = ippGetString(attr, 0, NULL);
70
+
71
+ ippDelete(response);
72
+ }
73
+ httpClose(http);
74
+ }
75
+ }
76
+ cupsFreeDests(num_dests, dests);
77
+ return info;
78
+ }
79
+
80
+ std::vector<PrinterInfo> MacPrinter::GetPrinters()
81
+ {
82
+ std::vector<PrinterInfo> printers;
83
+ cups_dest_t *dests;
84
+ int num_dests = cupsGetDests(&dests);
85
+
86
+ for (int i = 0; i < num_dests; i++)
87
+ {
88
+ printers.push_back(GetPrinterDetails(dests[i].name, dests[i].is_default));
89
+ }
90
+
91
+ cupsFreeDests(num_dests, dests);
92
+ return printers;
93
+ }
94
+
95
+ PrinterInfo MacPrinter::GetSystemDefaultPrinter()
96
+ {
97
+ cups_dest_t *dests;
98
+ int num_dests = cupsGetDests(&dests);
99
+ cups_dest_t *dest = cupsGetDest(NULL, NULL, num_dests, dests);
100
+
101
+ PrinterInfo printer;
102
+ if (dest != NULL)
103
+ {
104
+ printer = GetPrinterDetails(dest->name, true);
105
+ }
106
+
107
+ cupsFreeDests(num_dests, dests);
108
+ return printer;
109
+ }
110
+
111
+ bool MacPrinter::PrintDirect(const std::string &printerName,
112
+ const std::vector<uint8_t> &data,
113
+ const std::string &dataType)
114
+ {
115
+ int jobId = cupsCreateJob(CUPS_HTTP_DEFAULT, printerName.c_str(),
116
+ "Node.js Print Job", 0, NULL);
117
+
118
+ if (jobId <= 0)
119
+ return false;
120
+
121
+ http_status_t status = cupsStartDocument(CUPS_HTTP_DEFAULT, printerName.c_str(),
122
+ jobId, "Node.js Print Job",
123
+ dataType.c_str(), 1);
124
+
125
+ if (status != HTTP_STATUS_CONTINUE)
126
+ {
127
+ cupsCancelJob(printerName.c_str(), jobId);
128
+ return false;
129
+ }
130
+
131
+ if (cupsWriteRequestData(CUPS_HTTP_DEFAULT,
132
+ reinterpret_cast<const char *>(data.data()),
133
+ data.size()) != HTTP_STATUS_CONTINUE)
134
+ {
135
+ cupsCancelJob(printerName.c_str(), jobId);
136
+ return false;
137
+ }
138
+
139
+ status = static_cast<http_status_t>(cupsFinishDocument(CUPS_HTTP_DEFAULT, printerName.c_str()));
140
+ return status == HTTP_STATUS_OK;
141
+ }
142
+
143
+ PrinterInfo MacPrinter::GetStatusPrinter(const std::string &printerName)
144
+ {
145
+ cups_dest_t *dests;
146
+ int num_dests = cupsGetDests(&dests);
147
+
148
+ cups_dest_t *defaultDest = cupsGetDest(NULL, NULL, num_dests, dests);
149
+ bool isDefault = false;
150
+
151
+ if (defaultDest != NULL)
152
+ {
153
+ isDefault = (printerName == defaultDest->name);
154
+ }
155
+
156
+ cups_dest_t *dest = cupsGetDest(printerName.c_str(), NULL, num_dests, dests);
157
+ PrinterInfo printer;
158
+
159
+ if (dest != NULL)
160
+ {
161
+ printer = GetPrinterDetails(printerName, isDefault);
162
+ }
163
+
164
+ cupsFreeDests(num_dests, dests);
165
+ return printer;
166
+ }
@@ -0,0 +1,22 @@
1
+ #ifndef MAC_PRINTER_H
2
+ #define MAC_PRINTER_H
3
+
4
+ #include <cups/cups.h>
5
+ #include <cups/ppd.h>
6
+ #include <cstdint>
7
+ #include "printer_interface.h"
8
+
9
+ class MacPrinter : public PrinterInterface
10
+ {
11
+ private:
12
+ std::string GetPrinterStatus(ipp_pstate_t state);
13
+
14
+ public:
15
+ virtual PrinterInfo GetPrinterDetails(const std::string &printerName, bool isDefault = false) override;
16
+ virtual std::vector<PrinterInfo> GetPrinters() override;
17
+ virtual PrinterInfo GetSystemDefaultPrinter() override;
18
+ virtual bool PrintDirect(const std::string &printerName, const std::vector<uint8_t> &data, const std::string &dataType) override;
19
+ virtual PrinterInfo GetStatusPrinter(const std::string &printerName) override;
20
+ };
21
+
22
+ #endif
package/src/main.cpp ADDED
@@ -0,0 +1,22 @@
1
+ #include <napi.h>
2
+ #include "printer_factory.h"
3
+
4
+ Napi::Value PrintDirect(const Napi::CallbackInfo &info);
5
+ Napi::Value GetPrinters(const Napi::CallbackInfo &info);
6
+ Napi::Value GetSystemDefaultPrinter(const Napi::CallbackInfo &info);
7
+ Napi::Value GetStatusPrinter(const Napi::CallbackInfo &info);
8
+
9
+ Napi::Object Init(Napi::Env env, Napi::Object exports)
10
+ {
11
+ exports.Set(Napi::String::New(env, "printDirect"),
12
+ Napi::Function::New(env, PrintDirect));
13
+ exports.Set(Napi::String::New(env, "getPrinters"),
14
+ Napi::Function::New(env, GetPrinters));
15
+ exports.Set(Napi::String::New(env, "getDefaultPrinter"),
16
+ Napi::Function::New(env, GetSystemDefaultPrinter));
17
+ exports.Set(Napi::String::New(env, "getStatusPrinter"),
18
+ Napi::Function::New(env, GetStatusPrinter));
19
+ return exports;
20
+ }
21
+
22
+ NODE_API_MODULE(electron_printer, Init)
package/src/print.cpp ADDED
@@ -0,0 +1,272 @@
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
+ // Só 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
+ }
@@ -0,0 +1,20 @@
1
+ #include "printer_factory.h"
2
+
3
+ #ifdef _WIN32
4
+ #include "windows_printer.h"
5
+ #elif defined(__APPLE__)
6
+ #include "mac_printer.h"
7
+ #else
8
+ #include "linux_printer.h"
9
+ #endif
10
+
11
+ std::unique_ptr<PrinterInterface> PrinterFactory::Create()
12
+ {
13
+ #ifdef _WIN32
14
+ return std::make_unique<WindowsPrinter>();
15
+ #elif defined(__APPLE__)
16
+ return std::make_unique<MacPrinter>();
17
+ #else
18
+ return std::make_unique<LinuxPrinter>();
19
+ #endif
20
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef PRINTER_FACTORY_H
2
+ #define PRINTER_FACTORY_H
3
+
4
+ #include "printer_interface.h"
5
+ #include <memory>
6
+
7
+ class PrinterFactory
8
+ {
9
+ public:
10
+ static std::unique_ptr<PrinterInterface> Create();
11
+ };
12
+
13
+ #endif
@@ -0,0 +1,29 @@
1
+ #ifndef PRINTER_INTERFACE_H
2
+ #define PRINTER_INTERFACE_H
3
+
4
+ #include <string>
5
+ #include <vector>
6
+ #include <map>
7
+ #include <cstdint>
8
+
9
+ struct PrinterInfo
10
+ {
11
+ std::string name;
12
+ bool isDefault;
13
+ std::map<std::string, std::string> details;
14
+ std::string status;
15
+ };
16
+
17
+ class PrinterInterface
18
+ {
19
+ public:
20
+ virtual ~PrinterInterface() = default;
21
+
22
+ virtual PrinterInfo GetPrinterDetails(const std::string &printerName, bool isDefault = false) = 0;
23
+ virtual std::vector<PrinterInfo> GetPrinters() = 0;
24
+ virtual PrinterInfo GetSystemDefaultPrinter() = 0;
25
+ virtual bool PrintDirect(const std::string &printerName, const std::vector<uint8_t> &data, const std::string &dataType) = 0;
26
+ virtual PrinterInfo GetStatusPrinter(const std::string &printerName) = 0;
27
+ };
28
+
29
+ #endif