Skip to content

Commit 4608d05

Browse files
committed
connect hterm and tty with napi
1 parent f96eecc commit 4608d05

File tree

3 files changed

+154
-27
lines changed

3 files changed

+154
-27
lines changed

entry/src/main/cpp/napi_init.cpp

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <algorithm>
33
#include <array>
44
#include <assert.h>
5+
#include <bits/alltypes.h>
56
#include <cstdint>
67
#include <deque>
78
#include <fcntl.h>
@@ -17,12 +18,16 @@
1718
#include <unistd.h>
1819
#include <vector>
1920

20-
static int width = 127;
21-
static int height = 36;
21+
#include "hilog/log.h"
22+
23+
#undef LOG_DOMAIN
24+
#undef LOG_TAG
25+
#define LOG_DOMAIN 0x3200
26+
#define LOG_TAG "NapiTerminal"
2227

2328
static int fd = -1;
2429

25-
static napi_value Add(napi_env env, napi_callback_info info) {
30+
static napi_value add(napi_env env, napi_callback_info info) {
2631
size_t argc = 2;
2732
napi_value args[2] = {nullptr};
2833

@@ -46,10 +51,55 @@ static napi_value Add(napi_env env, napi_callback_info info) {
4651
return sum;
4752
}
4853

49-
static void *terminal_worker(void *) {}
54+
napi_threadsafe_function registered_callback = nullptr;
5055

51-
static napi_value Run(napi_env env, napi_callback_info info) {
56+
struct data_buffer {
57+
char *buf;
58+
size_t size;
59+
};
5260

61+
static void *terminal_worker(void *) {
62+
63+
while (true) {
64+
65+
struct pollfd fds[1];
66+
fds[0].fd = fd;
67+
fds[0].events = POLLIN;
68+
int res = poll(fds, 1, 100);
69+
70+
uint8_t buffer[1024];
71+
if (res > 0) {
72+
ssize_t r = read(fd, buffer, sizeof(buffer) - 1);
73+
if (r > 0) {
74+
// pretty print
75+
std::string hex;
76+
for (int i = 0; i < r; i++) {
77+
if (buffer[i] >= 127 || buffer[i] < 32) {
78+
char temp[8];
79+
snprintf(temp, sizeof(temp), "\\x%02x", buffer[i]);
80+
hex += temp;
81+
} else {
82+
hex += (char)buffer[i];
83+
}
84+
}
85+
86+
if (hex.length() > 0 && registered_callback != nullptr) {
87+
data_buffer *pbuf = new data_buffer{.buf = new char[hex.length()], .size = (size_t)hex.length()};
88+
memcpy(pbuf->buf, &hex[0], hex.length());
89+
napi_call_threadsafe_function(registered_callback, pbuf, napi_tsfn_nonblocking);
90+
}
91+
92+
OH_LOG_INFO(LOG_APP, "Got: %{public}s", hex.c_str());
93+
} else if (r < 0) {
94+
95+
OH_LOG_INFO(LOG_APP, "Program exited: %{public}ld %{public}d", r, errno);
96+
}
97+
}
98+
}
99+
}
100+
101+
static napi_value run(napi_env env, napi_callback_info info) {
102+
53103
size_t argc = 2;
54104
napi_value args[2] = {nullptr};
55105

@@ -67,10 +117,11 @@ static napi_value Run(napi_env env, napi_callback_info info) {
67117
double value1;
68118
napi_get_value_double(env, args[1], &value1);
69119

70-
width = value0;
71-
height = value1;
120+
int width = value0;
121+
int height = value1;
122+
123+
if (fd < 0) {
72124

73-
if (!fd) {
74125
struct winsize ws = {};
75126
ws.ws_col = width;
76127
ws.ws_row = height;
@@ -104,20 +155,77 @@ static napi_value send(napi_env env, napi_callback_info info) {
104155
napi_value args[1] = {nullptr};
105156
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
106157

107-
void *data;
158+
char *data;
108159
size_t length;
109-
napi_status ret = napi_get_arraybuffer_info(env, args[0], &data, &length);
160+
napi_status ret = napi_get_arraybuffer_info(env, args[0], (void **)&data, &length);
110161
assert(ret == napi_ok);
111162

112-
// SendData((uint8_t *)data, length);
163+
std::string hex;
164+
for (int i = 0; i < length; i++) {
165+
if (data[i] >= 127 || data[i] < 32) {
166+
char temp[8];
167+
snprintf(temp, sizeof(temp), "\\x%02x", data[i]);
168+
hex += temp;
169+
} else {
170+
hex += (char)data[i];
171+
}
172+
}
173+
OH_LOG_INFO(LOG_APP, "Send: %{public}s", hex.c_str());
174+
175+
if (fd > 0) {
176+
int written = 0;
177+
while (written < length) {
178+
int size = write(fd, (uint8_t *)data + written, length - written);
179+
assert(size >= 0);
180+
written += size;
181+
}
182+
}
183+
184+
return nullptr;
185+
}
186+
187+
void real_func_call_js(napi_env env, napi_value js_callback, void *context, void *data) {
188+
189+
data_buffer *buffer = static_cast<data_buffer *>(data);
190+
191+
napi_value ab;
192+
char *input;
193+
napi_create_arraybuffer(env, buffer->size, (void **)&input, &ab);
194+
memcpy(input, buffer->buf, buffer->size);
195+
196+
napi_value global;
197+
napi_get_global(env, &global);
198+
199+
napi_value result;
200+
napi_value args[1] = {ab};
201+
napi_call_function(env, global, js_callback, 1, args, &result);
202+
203+
delete[] buffer->buf;
204+
delete buffer;
205+
}
206+
207+
static napi_value register_callback(napi_env env, napi_callback_info info) {
208+
209+
size_t argc = 1;
210+
napi_value args[1];
211+
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
212+
213+
napi_value src_cb_name;
214+
napi_create_string_utf8(env, "data_callback", NAPI_AUTO_LENGTH, &src_cb_name);
215+
216+
napi_create_threadsafe_function(env, args[0], nullptr, src_cb_name, 0, 1, nullptr, nullptr, nullptr,
217+
real_func_call_js, &registered_callback);
218+
113219
return nullptr;
114220
}
115221

116222
EXTERN_C_START
117223
static napi_value Init(napi_env env, napi_value exports) {
118-
napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
119-
{"run", nullptr, Run, nullptr, nullptr, nullptr, napi_default, nullptr},
120-
{"send", nullptr, send, nullptr, nullptr, nullptr, napi_default, nullptr}};
224+
napi_property_descriptor desc[] = {
225+
{"add", nullptr, add, nullptr, nullptr, nullptr, napi_default, nullptr},
226+
{"run", nullptr, run, nullptr, nullptr, nullptr, napi_default, nullptr},
227+
{"send", nullptr, send, nullptr, nullptr, nullptr, napi_default, nullptr},
228+
{"subscribe", nullptr, register_callback, nullptr, nullptr, nullptr, napi_default, nullptr}};
121229
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
122230
return exports;
123231
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
export const add: (a: number, b: number) => number;
1+
export const add: (a: number, b: number) => number;
2+
export const run: (w: number, h: number) => void;
3+
export const send: (content: ArrayBuffer) => void;
4+
export const subscribe: (cb: (ArrayBuffer) => void) => void;

entry/src/main/ets/pages/Index.ets

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import util from '@ohos.util';
2+
import { buffer } from '@kit.ArkTS';
13
import { webview } from '@kit.ArkWeb';
24
import { hilog } from '@kit.PerformanceAnalysisKit';
35
import napi from 'libentry.so';
@@ -9,6 +11,11 @@ interface Size {
911
height: number
1012
}
1113

14+
function stringToArrayBuffer(str: string, encoding: buffer.BufferEncoding = 'utf-8'): ArrayBuffer {
15+
const buf = buffer.from(str, encoding);
16+
return buf.buffer;
17+
}
18+
1219
class NativeProxy {
1320
webviewController: webview.WebviewController
1421

@@ -17,47 +24,56 @@ class NativeProxy {
1724
}
1825

1926
propUpdate(key: object, value: object): void {
20-
hilog.info(DOMAIN, 'native', '%{public}s', 'propUpdate: ' + key + ", value: " + value);
27+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'propUpdate: ' + key + ", value: " + value);
2128
}
2229

2330
sendInput(data: string): void {
24-
hilog.info(DOMAIN, 'native', '%{public}s', 'sendInput: ' + data);
25-
this.webviewController.runJavaScript('exports.write("' + data + '")')
31+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'sendInput: ' + data);
32+
let buffer = stringToArrayBuffer(data, 'utf-8');
33+
napi.send(buffer)
2634
}
2735

2836
async resize(): Promise<void> {
2937
const s = await this.getSize();
30-
hilog.info(DOMAIN, 'native', '%{public}s', 'resize: ' + s.width + ", " + s.height)
38+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'resize: ' + s.width + ", " + s.height)
3139
}
3240

3341
focus(): void {
34-
hilog.info(DOMAIN, 'native', '%{public}s', 'focus')
42+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'focus')
3543
}
3644

3745
syncFocus(): void {
38-
hilog.info(DOMAIN, 'native', '%{public}s', 'syncFocus')
46+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'syncFocus')
3947
}
4048

4149
newScrollHeight(h: number): void {
42-
hilog.info(DOMAIN, 'native', '%{public}s', 'newScrollHeight: ' + h)
50+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'newScrollHeight: ' + h)
4351
}
4452

4553
newScrollTop(h: number): void {
46-
hilog.info(DOMAIN, 'native', '%{public}s', 'newScrollTop: ' + h)
54+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'newScrollTop: ' + h)
4755
}
4856

4957
openLink(url: string): void {
50-
hilog.info(DOMAIN, 'native', '%{public}s', 'openLink: ' + url)
58+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'openLink: ' + url)
5159
}
5260

5361
async load(): Promise<void> {
54-
hilog.info(DOMAIN, 'native', '%{public}s', 'load')
55-
this.webviewController.runJavaScript('exports.write("shell")')
62+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'load')
5663
this.webviewController.runJavaScript('exports.setFocused(true)')
5764

5865
const s: Size = await this.getSize();
5966

60-
console.log('w: ' + s.width + ', h: ' + s.height)
67+
napi.subscribe((a: ArrayBuffer) => {
68+
let dec = util.TextDecoder.create('utf-8', { ignoreBOM: true })
69+
let s: string = dec.decodeToString(new Uint8Array(a))
70+
71+
hilog.info(DOMAIN, 'WebTerminal', '%{public}s', 'write: ' + s)
72+
73+
this.webviewController.runJavaScript('exports.write("' + s + '")')
74+
})
75+
76+
napi.run(s.width, s.height)
6177
}
6278

6379
private async getSize(): Promise<Size> {

0 commit comments

Comments
 (0)