@makano/rew 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +3 -0
- package/bin/rew +1 -8
- package/lib/rew/cli/cli.js +42 -50
- package/lib/rew/cli/run.js +4 -11
- package/lib/rew/cli/utils.js +130 -53
- package/lib/rew/const/default.js +6 -1
- package/lib/rew/const/files.js +3 -9
- package/lib/rew/const/pre-exec.js +3 -0
- package/lib/rew/functions/import.js +4 -3
- package/lib/rew/functions/misc.js +5 -0
- package/lib/rew/functions/sleep.js +1 -1
- package/lib/rew/functions/stdout.js +7 -4
- package/lib/rew/functions/wait.js +11 -0
- package/lib/rew/modules/compiler.js +9 -7
- package/lib/rew/modules/context.js +1 -1
- package/lib/rew/modules/runtime.js +21 -2
- package/lib/rew/pkgs/conf.js +8 -1
- package/lib/rew/pkgs/rune.js +12 -6
- package/main.js +13 -0
- package/package.json +5 -6
- package/bin/ui +0 -0
- package/bin/ui_ws +0 -0
- package/bin/webkit_app +0 -0
- package/build.sh +0 -8
- package/cpp/ui.cpp +0 -217
- package/cpp/ui1.cpp +0 -101
- package/cpp/ui2.cpp +0 -105
- package/lib/rew/css/theme.css +0 -3
- package/lib/rew/html/ui.html +0 -18
- package/lib/rew/html/ui.js +0 -245
- package/lib/rew/pkgs/modules/ui/classes.js +0 -184
- package/lib/rew/pkgs/ui.js +0 -157
- package/meson.build +0 -13
@@ -0,0 +1,11 @@
|
|
1
|
+
const deasync = require("deasync");
|
2
|
+
|
3
|
+
|
4
|
+
module.exports.wait = (...args) => {
|
5
|
+
const fn = args.shift();
|
6
|
+
if(typeof fn !== "function") throw new TypeError("The first argument must be a function to use wait.");
|
7
|
+
const df = deasync(async (cb) => {
|
8
|
+
cb(null, await fn(...args));
|
9
|
+
});
|
10
|
+
return df();
|
11
|
+
}
|
@@ -22,7 +22,8 @@ function tokenizeCoffeeScript(code) {
|
|
22
22
|
type: 'COMMENT',
|
23
23
|
value: char + code.substring(i + 1).split('\n')[0] + '\n',
|
24
24
|
});
|
25
|
-
|
25
|
+
const ind = code.indexOf('\n', i);
|
26
|
+
i = ind < 0 ? code.length-1 : ind;
|
26
27
|
} else if (char === '"' || char === "'") {
|
27
28
|
// String
|
28
29
|
let string = char;
|
@@ -56,11 +57,11 @@ function tokenizeCoffeeScript(code) {
|
|
56
57
|
} else {
|
57
58
|
tokens.push({ type: 'WHITESPACE', value: char });
|
58
59
|
}
|
59
|
-
} else if (/[a-zA-
|
60
|
+
} else if (/[a-zA-Z\._$]/.test(char)) {
|
60
61
|
// Identifier
|
61
62
|
let identifier = char;
|
62
63
|
i++;
|
63
|
-
while (i < code.length && /[a-zA-Z0-
|
64
|
+
while (i < code.length && /[a-zA-Z0-9\._$]/.test(code[i])) {
|
64
65
|
identifier += code[i];
|
65
66
|
i++;
|
66
67
|
}
|
@@ -176,7 +177,7 @@ function compileRewStuff(content, options) {
|
|
176
177
|
} else if (nextToken) {
|
177
178
|
const nameToken = fnextToken(ind, tokens, 'STRING');
|
178
179
|
defaultName = nextToken.value;
|
179
|
-
let {
|
180
|
+
let { token: nextNextToken, n: n2 } = gnextToken(i + 2, 1, tokens) || {};
|
180
181
|
if (nextNextToken?.type == 'OTHER' && nextNextToken?.value == ',') {
|
181
182
|
const closingBraceToken = fnextToken(ind, tokens, 'OTHER', '}');
|
182
183
|
if (closingBraceToken) {
|
@@ -235,12 +236,13 @@ function compileRewStuff(content, options) {
|
|
235
236
|
}
|
236
237
|
|
237
238
|
const cpl = (module.exports.compile = function (file, options = {}) {
|
238
|
-
let c = compile(compileRewStuff(file.content, options), {
|
239
|
+
let c = options.type == 'js' || options.compile == false ? file.content : compile(compileRewStuff(file.content, options), {
|
239
240
|
...options,
|
240
241
|
filename: file.path,
|
241
242
|
bare: false,
|
242
243
|
inlineMap: false,
|
243
244
|
});
|
245
|
+
// console.log(c);
|
244
246
|
if (execOptions.jsx || options.jsx) {
|
245
247
|
c = babel.transformSync(c, {
|
246
248
|
presets: [[babelReact, { pragma: execOptions.jsxPragma }]],
|
@@ -254,10 +256,10 @@ module.exports.compileFile = function (filepath, options = {}) {
|
|
254
256
|
const f = getFile(filepath);
|
255
257
|
|
256
258
|
if(options.qrew || path.extname(filepath) == '.qrew') {
|
257
|
-
f.content = from_qrew(readFileSync(f.path), options.package || findAppInfo(filepath)?.config.package || path.basename(filepath).split('.').slice(0, -1).join('.')).toString();
|
259
|
+
f.content = from_qrew(readFileSync(f.path), options.package || findAppInfo(filepath)?.config.manifest.package || path.basename(filepath).split('.').slice(0, -1).join('.')).toString();
|
258
260
|
}
|
259
261
|
|
260
|
-
let compiled_code =
|
262
|
+
let compiled_code = cpl(f, { ...options });
|
261
263
|
|
262
264
|
return {
|
263
265
|
compiled_code,
|
@@ -60,7 +60,7 @@ module.exports.prepareContext = function (
|
|
60
60
|
}
|
61
61
|
if (!context.process)
|
62
62
|
context.process = {
|
63
|
-
argv: process.argv,
|
63
|
+
argv: options.argv || process.argv,
|
64
64
|
target: {
|
65
65
|
on: (event, listener) => process.on(event, listener),
|
66
66
|
off: (event, listener) => process.off(event, listener),
|
@@ -1,22 +1,41 @@
|
|
1
1
|
const vm = require('vm');
|
2
2
|
const { compileFile } = require('./compiler');
|
3
3
|
const { prepareContext } = require('./context');
|
4
|
+
const { existsSync, readFileSync } = require('fs');
|
5
|
+
const { CONFIG_PATH } = require('../const/config_path');
|
6
|
+
const path = require('path');
|
7
|
+
|
8
|
+
const preScript = readFileSync(path.join(__dirname, '../const/pre-exec.js'), { encoding: 'utf-8' });
|
4
9
|
|
5
10
|
const exec = (module.exports.exec = function (code, context) {
|
6
11
|
return vm.runInNewContext(code, vm.createContext(context), {
|
7
12
|
filename: context.module.filepath,
|
8
|
-
lineOffset:
|
13
|
+
lineOffset: -1 - preScript.split('\n').length,
|
9
14
|
displayErrors: true,
|
10
15
|
});
|
11
16
|
});
|
12
17
|
|
13
18
|
module.exports.runPath = function runPath(filepath, options = {}, custom_context = {}) {
|
14
|
-
|
19
|
+
if(filepath.endsWith('.js')) options.type = 'js';
|
20
|
+
let { compiled_code, file } = compileFile(filepath, options);
|
15
21
|
const context = prepareContext(custom_context, options, file.path, runPath);
|
16
22
|
|
17
23
|
context.module.compiled = compiled_code;
|
18
24
|
context.process.exit = (int) => process.exit(int);
|
19
25
|
|
26
|
+
if(context.app){
|
27
|
+
const p = path.join(CONFIG_PATH, context.app.config.manifest.package, 'app');
|
28
|
+
if(existsSync(p) && context.app.path !== p){
|
29
|
+
console.log("App with the same package name has been installed. Conflicts happened. \nTo fix this, change your app's package name or remove the app making the conflict.");
|
30
|
+
return {
|
31
|
+
context: { exports: null },
|
32
|
+
returns: null
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
compiled_code = preScript+compiled_code;
|
38
|
+
|
20
39
|
return {
|
21
40
|
context,
|
22
41
|
returns: exec(compiled_code, context),
|
package/lib/rew/pkgs/conf.js
CHANGED
@@ -49,9 +49,16 @@ module.exports = (context) => ({
|
|
49
49
|
const fileRoot = path.join(rootPath, name);
|
50
50
|
const exists = fs.existsSync(fileRoot);
|
51
51
|
return {
|
52
|
-
|
52
|
+
write(value, ifExists) {
|
53
53
|
if (!fs.existsSync(path.dirname(fileRoot))) fs.mkdirSync(path.dirname(fileRoot), { recursive: true });
|
54
|
+
if(ifExists && fs.existsSync(fileRoot)) return this;
|
54
55
|
fs.writeFileSync(fileRoot, value || defaultValue);
|
56
|
+
return this;
|
57
|
+
},
|
58
|
+
read(s){
|
59
|
+
let file = fs.readFileSync(fileRoot);
|
60
|
+
return typeof s == "string" ? file.toString() :
|
61
|
+
typeof s == "object" ? file.toJSON() : file;
|
55
62
|
},
|
56
63
|
fileRoot,
|
57
64
|
exists,
|
package/lib/rew/pkgs/rune.js
CHANGED
@@ -347,7 +347,10 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
347
347
|
|
348
348
|
const remove = (key) => {
|
349
349
|
if (!fs.existsSync(mapFilePath)) return false;
|
350
|
-
|
350
|
+
let data = {};
|
351
|
+
if (fs.existsSync(mapFilePath)) {
|
352
|
+
data = readDataFile(mapFilePath);
|
353
|
+
}
|
351
354
|
if (data[key]) {
|
352
355
|
delete data[key];
|
353
356
|
writeDataFile(mapFilePath, data);
|
@@ -356,8 +359,11 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
356
359
|
return false;
|
357
360
|
};
|
358
361
|
|
359
|
-
const transform = (cb, mutate =
|
360
|
-
|
362
|
+
const transform = (cb, mutate = true) => {
|
363
|
+
let data = {};
|
364
|
+
if (fs.existsSync(mapFilePath)) {
|
365
|
+
data = readDataFile(mapFilePath);
|
366
|
+
}
|
361
367
|
const transformedData = cb(data);
|
362
368
|
if (mutate) {
|
363
369
|
writeDataFile(mapFilePath, transformedData);
|
@@ -386,7 +392,7 @@ module.exports = (context) => ({
|
|
386
392
|
},
|
387
393
|
db(dbname, data = {}, encryptionKey) {
|
388
394
|
if (!context.app) throw new Error('rune can only be used in apps');
|
389
|
-
const pkg = path.join(CONFIG_PATH, context.app.config.package, 'db');
|
395
|
+
const pkg = path.join(CONFIG_PATH, context.app.config.manifest.package, 'db');
|
390
396
|
if (!fs.existsSync(pkg)) fs.mkdirSync(pkg, { recursive: true });
|
391
397
|
return createDB(dbname, pkg, data, encryptionKey || ENCRYPTION_KEY);
|
392
398
|
},
|
@@ -394,7 +400,7 @@ module.exports = (context) => ({
|
|
394
400
|
return gen_key(secret);
|
395
401
|
},
|
396
402
|
makeRef,
|
397
|
-
|
398
|
-
|
403
|
+
push: runePush,
|
404
|
+
pop: runePop,
|
399
405
|
createDB,
|
400
406
|
});
|
package/main.js
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
const utils = require("./lib/rew/cli/utils");
|
3
|
+
const { run } = require("./lib/rew/main");
|
4
|
+
const { compileFile, compile } = require("./lib/rew/modules/compiler");
|
5
|
+
const pkgs = require("./lib/rew/pkgs/pkgs");
|
6
|
+
|
7
|
+
module.exports = {
|
8
|
+
compile,
|
9
|
+
compileFile,
|
10
|
+
run,
|
11
|
+
pkgs,
|
12
|
+
utils
|
13
|
+
};
|
package/package.json
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
{
|
2
2
|
"name": "@makano/rew",
|
3
|
-
"version": "1.2.
|
3
|
+
"version": "1.2.3",
|
4
4
|
"description": "A simple coffescript runtime and app manager",
|
5
|
-
"main": "
|
5
|
+
"main": "main.js",
|
6
6
|
"directories": {
|
7
7
|
"lib": "lib"
|
8
8
|
},
|
@@ -11,10 +11,7 @@
|
|
11
11
|
},
|
12
12
|
"files": [
|
13
13
|
"lib/",
|
14
|
-
"
|
15
|
-
"bin/",
|
16
|
-
"meson.build",
|
17
|
-
"build.sh",
|
14
|
+
"main.js",
|
18
15
|
"README.md"
|
19
16
|
],
|
20
17
|
"bin": {
|
@@ -34,10 +31,12 @@
|
|
34
31
|
"dependencies": {
|
35
32
|
"@babel/core": "^7.24.6",
|
36
33
|
"@babel/preset-react": "^7.24.6",
|
34
|
+
"@babel/preset-typescript": "^7.24.7",
|
37
35
|
"axios": "^1.7.2",
|
38
36
|
"babel-plugin-jsx": "^1.2.0",
|
39
37
|
"chokidar": "^3.6.0",
|
40
38
|
"colors": "^1.4.0",
|
39
|
+
"deasync": "^0.1.30",
|
41
40
|
"js-yaml": "^4.1.0",
|
42
41
|
"tiny-msgpack": "^2.2.0",
|
43
42
|
"uuid": "^9.0.1",
|
package/bin/ui
DELETED
Binary file
|
package/bin/ui_ws
DELETED
Binary file
|
package/bin/webkit_app
DELETED
Binary file
|
package/build.sh
DELETED
package/cpp/ui.cpp
DELETED
@@ -1,217 +0,0 @@
|
|
1
|
-
#include <gtk/gtk.h>
|
2
|
-
#include <webkit2/webkit2.h>
|
3
|
-
#include <json/json.h>
|
4
|
-
#include <iostream>
|
5
|
-
#include <sstream>
|
6
|
-
#include <string>
|
7
|
-
#include <fstream>
|
8
|
-
#include <thread>
|
9
|
-
#include <sys/inotify.h>
|
10
|
-
#include <unistd.h>
|
11
|
-
#include <vector>
|
12
|
-
|
13
|
-
struct AppData
|
14
|
-
{
|
15
|
-
GtkWidget *window;
|
16
|
-
WebKitWebView *web_view;
|
17
|
-
WebKitUserContentManager *content_manager;
|
18
|
-
};
|
19
|
-
|
20
|
-
static void handle_json_message(const Json::Value &json, AppData *user_data)
|
21
|
-
{
|
22
|
-
if (json.isMember("action") && json.isMember("data"))
|
23
|
-
{
|
24
|
-
std::string action = json["action"].asString();
|
25
|
-
std::string data = json["data"].asString();
|
26
|
-
|
27
|
-
// std::cout << action << std::endl;
|
28
|
-
|
29
|
-
if (action == "setTitle")
|
30
|
-
{
|
31
|
-
gtk_window_set_title(GTK_WINDOW(user_data->window), data.c_str());
|
32
|
-
}
|
33
|
-
else if (action == "log")
|
34
|
-
{
|
35
|
-
g_print("%s\n", data.c_str());
|
36
|
-
}
|
37
|
-
else if (action == "HTML")
|
38
|
-
{
|
39
|
-
webkit_web_view_load_html(user_data->web_view, data.c_str(), NULL);
|
40
|
-
g_print("SETUP::HTML");
|
41
|
-
}
|
42
|
-
else if (action == "JS")
|
43
|
-
{
|
44
|
-
webkit_web_view_run_javascript(user_data->web_view, data.c_str(), NULL, NULL, NULL);
|
45
|
-
}
|
46
|
-
else if (action == "JS2")
|
47
|
-
{
|
48
|
-
const char *js_code = g_strdup_printf("%s;", data.c_str());
|
49
|
-
WebKitUserScript *user_script = webkit_user_script_new(js_code,
|
50
|
-
WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
|
51
|
-
WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START,
|
52
|
-
NULL, NULL);
|
53
|
-
webkit_user_content_manager_add_script(user_data->content_manager, user_script);
|
54
|
-
}
|
55
|
-
}
|
56
|
-
else
|
57
|
-
{
|
58
|
-
g_print("Invalid JSON format: 'action' and 'data' fields are required\n");
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
static void js_callback(WebKitUserContentManager *manager,
|
63
|
-
WebKitJavascriptResult *js_result,
|
64
|
-
gpointer user_data)
|
65
|
-
{
|
66
|
-
JSCValue *value = webkit_javascript_result_get_js_value(js_result);
|
67
|
-
if (jsc_value_is_string(value))
|
68
|
-
{
|
69
|
-
char *str_value = jsc_value_to_string(value);
|
70
|
-
|
71
|
-
Json::Value root;
|
72
|
-
Json::CharReaderBuilder builder;
|
73
|
-
std::string errors;
|
74
|
-
std::istringstream json_stream(str_value);
|
75
|
-
bool success = Json::parseFromStream(builder, json_stream, &root, &errors);
|
76
|
-
|
77
|
-
if (success)
|
78
|
-
{
|
79
|
-
handle_json_message(root, static_cast<AppData *>(user_data));
|
80
|
-
}
|
81
|
-
else
|
82
|
-
{
|
83
|
-
g_print("%s", str_value);
|
84
|
-
}
|
85
|
-
|
86
|
-
g_free(str_value);
|
87
|
-
}
|
88
|
-
}
|
89
|
-
|
90
|
-
void watch_file(const std::string &file_path, AppData *app_data)
|
91
|
-
{
|
92
|
-
int inotify_fd = inotify_init();
|
93
|
-
if (inotify_fd < 0)
|
94
|
-
{
|
95
|
-
perror("inotify_init");
|
96
|
-
return;
|
97
|
-
}
|
98
|
-
|
99
|
-
int watch_fd = inotify_add_watch(inotify_fd, file_path.c_str(), IN_MODIFY);
|
100
|
-
if (watch_fd < 0)
|
101
|
-
{
|
102
|
-
perror("inotify_add_watch");
|
103
|
-
close(inotify_fd);
|
104
|
-
return;
|
105
|
-
}
|
106
|
-
|
107
|
-
const size_t event_size = sizeof(struct inotify_event);
|
108
|
-
const size_t buf_len = 1024 * (event_size + 16);
|
109
|
-
std::vector<char> buffer(buf_len);
|
110
|
-
|
111
|
-
while (true)
|
112
|
-
{
|
113
|
-
int length = read(inotify_fd, buffer.data(), buf_len);
|
114
|
-
if (length < 0)
|
115
|
-
{
|
116
|
-
perror("read");
|
117
|
-
break;
|
118
|
-
}
|
119
|
-
|
120
|
-
for (int i = 0; i < length;)
|
121
|
-
{
|
122
|
-
struct inotify_event *event = reinterpret_cast<struct inotify_event *>(&buffer[i]);
|
123
|
-
if (event->mask & IN_MODIFY)
|
124
|
-
{
|
125
|
-
std::ifstream file(file_path);
|
126
|
-
std::stringstream buffer;
|
127
|
-
buffer << file.rdbuf();
|
128
|
-
std::string content = buffer.str();
|
129
|
-
file.close();
|
130
|
-
|
131
|
-
if (!content.empty())
|
132
|
-
{
|
133
|
-
Json::Value root;
|
134
|
-
Json::CharReaderBuilder builder;
|
135
|
-
std::string errors;
|
136
|
-
std::istringstream json_stream(content);
|
137
|
-
bool success = Json::parseFromStream(builder, json_stream, &root, &errors);
|
138
|
-
|
139
|
-
// std::cout << "CONTENT DETECTED" << std::endl;
|
140
|
-
|
141
|
-
if (success)
|
142
|
-
{
|
143
|
-
handle_json_message(root, app_data);
|
144
|
-
}
|
145
|
-
else
|
146
|
-
{
|
147
|
-
g_print("Failed to parse JSON string: %s\n", errors.c_str());
|
148
|
-
}
|
149
|
-
|
150
|
-
std::ofstream clear_file(file_path, std::ofstream::out | std::ofstream::trunc);
|
151
|
-
clear_file.close();
|
152
|
-
}
|
153
|
-
}
|
154
|
-
i += event_size + event->len;
|
155
|
-
}
|
156
|
-
}
|
157
|
-
|
158
|
-
close(watch_fd);
|
159
|
-
close(inotify_fd);
|
160
|
-
}
|
161
|
-
|
162
|
-
int main(int argc, char **argv)
|
163
|
-
{
|
164
|
-
if (argc != 2)
|
165
|
-
{
|
166
|
-
g_print("Usage: %s <RUNID>\n", argv[0]);
|
167
|
-
return 1;
|
168
|
-
}
|
169
|
-
|
170
|
-
const char *rid = argv[1];
|
171
|
-
std::string file_path = "/tmp/" + std::string(rid) + ".ruw.ui.socket";
|
172
|
-
|
173
|
-
AppData app_data;
|
174
|
-
|
175
|
-
gtk_init(&argc, &argv);
|
176
|
-
|
177
|
-
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
178
|
-
gtk_window_set_title(GTK_WINDOW(window), "WebKit Example");
|
179
|
-
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
|
180
|
-
|
181
|
-
app_data.window = window;
|
182
|
-
|
183
|
-
WebKitUserContentManager *content_manager = webkit_user_content_manager_new();
|
184
|
-
webkit_user_content_manager_register_script_message_handler(content_manager, "external");
|
185
|
-
g_signal_connect(content_manager, "script-message-received::external", G_CALLBACK(js_callback), &app_data);
|
186
|
-
app_data.content_manager = content_manager;
|
187
|
-
|
188
|
-
const char *js_code = g_strdup_printf("window.RUNID = \"%s\";", rid);
|
189
|
-
WebKitUserScript *user_script = webkit_user_script_new(js_code,
|
190
|
-
WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
|
191
|
-
WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START,
|
192
|
-
NULL, NULL);
|
193
|
-
webkit_user_content_manager_add_script(content_manager, user_script);
|
194
|
-
|
195
|
-
WebKitWebView *web_view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(content_manager));
|
196
|
-
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(web_view));
|
197
|
-
app_data.web_view = web_view;
|
198
|
-
|
199
|
-
webkit_web_view_load_html(web_view, "Loading...", NULL);
|
200
|
-
|
201
|
-
GIOChannel *channel = g_io_channel_unix_new(fileno(stdin));
|
202
|
-
GIOFlags flags = static_cast<GIOFlags>(g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK);
|
203
|
-
g_io_channel_set_flags(channel, flags, NULL);
|
204
|
-
|
205
|
-
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
206
|
-
|
207
|
-
std::thread watch_thread(watch_file, file_path, &app_data);
|
208
|
-
|
209
|
-
g_print("INIT::READY");
|
210
|
-
|
211
|
-
gtk_widget_show_all(window);
|
212
|
-
gtk_main();
|
213
|
-
|
214
|
-
watch_thread.detach();
|
215
|
-
|
216
|
-
return 0;
|
217
|
-
}
|
package/cpp/ui1.cpp
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
#include <gtk/gtk.h>
|
2
|
-
#include <webkit2/webkit2.h>
|
3
|
-
#include <json/json.h>
|
4
|
-
|
5
|
-
struct AppData {
|
6
|
-
const char* url;
|
7
|
-
GtkWidget* window;
|
8
|
-
};
|
9
|
-
|
10
|
-
static void handle_json_message(const Json::Value& json, AppData* user_data) {
|
11
|
-
// Check if the JSON object has the "action" and "data" fields
|
12
|
-
if (json.isMember("action") && json.isMember("data")) {
|
13
|
-
std::string action = json["action"].asString();
|
14
|
-
std::string data = json["data"].asString();
|
15
|
-
|
16
|
-
// Perform actions based on the received data
|
17
|
-
if (action == "setTitle") {
|
18
|
-
// Set the GTK window's title
|
19
|
-
gtk_window_set_title(GTK_WINDOW(user_data->window), data.c_str());
|
20
|
-
} else if (action == "log") {
|
21
|
-
// Set the GTK window's title
|
22
|
-
g_print("%s\n", data.c_str());
|
23
|
-
} else {
|
24
|
-
// Handle other actions as needed
|
25
|
-
}
|
26
|
-
} else {
|
27
|
-
// Invalid JSON format
|
28
|
-
g_print("Invalid JSON format: 'action' and 'data' fields are required\n");
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
static void js_callback(WebKitUserContentManager* manager,
|
33
|
-
WebKitJavascriptResult* js_result,
|
34
|
-
gpointer user_data) {
|
35
|
-
JSCValue* value = webkit_javascript_result_get_js_value(js_result);
|
36
|
-
if (jsc_value_is_string(value)) {
|
37
|
-
char* str_value = jsc_value_to_string(value);
|
38
|
-
|
39
|
-
Json::Value root;
|
40
|
-
Json::CharReaderBuilder builder;
|
41
|
-
std::string errors;
|
42
|
-
std::istringstream json_stream(str_value);
|
43
|
-
bool success = Json::parseFromStream(builder, json_stream, &root, &errors);
|
44
|
-
|
45
|
-
if (success) {
|
46
|
-
// Handle the incoming JSON message
|
47
|
-
handle_json_message(root, static_cast<AppData*>(user_data));
|
48
|
-
} else {
|
49
|
-
g_print("%s", str_value);
|
50
|
-
// g_print("Failed to parse JSON string: %s\n", errors.c_str());
|
51
|
-
}
|
52
|
-
|
53
|
-
g_free(str_value);
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
|
58
|
-
int main(int argc, char** argv) {
|
59
|
-
if (argc != 3) {
|
60
|
-
g_print("Usage: %s <URL> <RUNID>\n", argv[0]);
|
61
|
-
return 1;
|
62
|
-
}
|
63
|
-
|
64
|
-
const char* url = argv[1];
|
65
|
-
const char* rid = argv[2];
|
66
|
-
|
67
|
-
AppData app_data;
|
68
|
-
app_data.url = url;
|
69
|
-
|
70
|
-
gtk_init(&argc, &argv);
|
71
|
-
|
72
|
-
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
73
|
-
gtk_window_set_title(GTK_WINDOW(window), "WebKit Example");
|
74
|
-
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
|
75
|
-
|
76
|
-
app_data.window = window;
|
77
|
-
|
78
|
-
WebKitUserContentManager* content_manager = webkit_user_content_manager_new();
|
79
|
-
webkit_user_content_manager_register_script_message_handler(content_manager, "external");
|
80
|
-
g_signal_connect(content_manager, "script-message-received::external", G_CALLBACK(js_callback), &app_data);
|
81
|
-
|
82
|
-
const char* js_code = g_strdup_printf("window.RUNID = \"%s\";", rid);
|
83
|
-
WebKitUserScript* user_script = webkit_user_script_new(js_code,
|
84
|
-
WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
|
85
|
-
WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START,
|
86
|
-
NULL, NULL);
|
87
|
-
webkit_user_content_manager_add_script(content_manager, user_script);
|
88
|
-
|
89
|
-
WebKitWebView* web_view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(content_manager));
|
90
|
-
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(web_view));
|
91
|
-
|
92
|
-
webkit_web_view_load_uri(web_view, url);
|
93
|
-
|
94
|
-
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
95
|
-
|
96
|
-
gtk_widget_show_all(window);
|
97
|
-
|
98
|
-
gtk_main();
|
99
|
-
|
100
|
-
return 0;
|
101
|
-
}
|
package/cpp/ui2.cpp
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
#include <gtk/gtk.h>
|
2
|
-
#include <libwebsockets.h>
|
3
|
-
#include <json/json.h>
|
4
|
-
#include <iostream>
|
5
|
-
#include <string>
|
6
|
-
#include <map>
|
7
|
-
|
8
|
-
std::map<std::string, GtkWidget *> widgets;
|
9
|
-
|
10
|
-
static void on_button_clicked(GtkWidget *widget, gpointer data)
|
11
|
-
{
|
12
|
-
// Send event back to Node.js server
|
13
|
-
std::string id = static_cast<char *>(data);
|
14
|
-
std::string message = "{\"event\": \"buttonClicked\", \"id\": \"" + id + "\"}";
|
15
|
-
lws_write(static_cast<lws *>(data), (unsigned char *)message.c_str(), message.length(), LWS_WRITE_TEXT);
|
16
|
-
}
|
17
|
-
|
18
|
-
static int callback_websocket(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
19
|
-
{
|
20
|
-
switch (reason)
|
21
|
-
{
|
22
|
-
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
23
|
-
std::cout << "Connected to server" << std::endl;
|
24
|
-
break;
|
25
|
-
case LWS_CALLBACK_CLIENT_RECEIVE:
|
26
|
-
{
|
27
|
-
std::string message(static_cast<char *>(in), len);
|
28
|
-
Json::CharReaderBuilder rbuilder;
|
29
|
-
Json::Value root;
|
30
|
-
std::string errors;
|
31
|
-
|
32
|
-
std::istringstream s(message);
|
33
|
-
std::string doc;
|
34
|
-
std::getline(s, doc);
|
35
|
-
std::istringstream ss(doc);
|
36
|
-
if (Json::parseFromStream(rbuilder, ss, &root, &errors))
|
37
|
-
{
|
38
|
-
std::string action = root["action"].asString();
|
39
|
-
|
40
|
-
if (action == "createButton")
|
41
|
-
{
|
42
|
-
GtkWidget *button = gtk_button_new_with_label(root["label"].asString().c_str());
|
43
|
-
g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), strdup(root["id"].asString().c_str()));
|
44
|
-
widgets[root["id"].asString()] = button;
|
45
|
-
gtk_container_add(GTK_CONTAINER(gtk_window_new(GTK_WINDOW_TOPLEVEL)), button);
|
46
|
-
gtk_widget_show_all(button);
|
47
|
-
}
|
48
|
-
}
|
49
|
-
break;
|
50
|
-
}
|
51
|
-
case LWS_CALLBACK_CLIENT_CLOSED:
|
52
|
-
std::cout << "Disconnected from server" << std::endl;
|
53
|
-
break;
|
54
|
-
default:
|
55
|
-
break;
|
56
|
-
}
|
57
|
-
return 0;
|
58
|
-
}
|
59
|
-
|
60
|
-
static const struct lws_protocols protocols[] = {
|
61
|
-
{
|
62
|
-
"example-protocol",
|
63
|
-
callback_websocket,
|
64
|
-
0,
|
65
|
-
1024,
|
66
|
-
},
|
67
|
-
{NULL, NULL, 0, 0}};
|
68
|
-
|
69
|
-
int main(int argc, char **argv)
|
70
|
-
{
|
71
|
-
std::cout << "Starting" << std::endl;
|
72
|
-
if (argc != 2)
|
73
|
-
{
|
74
|
-
std::cerr << "Usage: " << argv[0] << " <WebSocket server URI>" << std::endl;
|
75
|
-
return 1;
|
76
|
-
}
|
77
|
-
|
78
|
-
gtk_init(&argc, &argv);
|
79
|
-
|
80
|
-
struct lws_context_creation_info info;
|
81
|
-
memset(&info, 0, sizeof info);
|
82
|
-
info.port = CONTEXT_PORT_NO_LISTEN;
|
83
|
-
info.protocols = protocols;
|
84
|
-
|
85
|
-
struct lws_context *context = lws_create_context(&info);
|
86
|
-
|
87
|
-
struct lws_client_connect_info ccinfo = {0};
|
88
|
-
ccinfo.context = context;
|
89
|
-
ccinfo.address = argv[1];
|
90
|
-
ccinfo.port = 8080;
|
91
|
-
ccinfo.path = "/";
|
92
|
-
ccinfo.host = lws_canonical_hostname(context);
|
93
|
-
ccinfo.origin = "origin";
|
94
|
-
ccinfo.protocol = protocols[0].name;
|
95
|
-
|
96
|
-
struct lws *wsi = lws_client_connect_via_info(&ccinfo);
|
97
|
-
|
98
|
-
while (lws_service(context, 1000) >= 0)
|
99
|
-
{
|
100
|
-
gtk_main_iteration_do(false);
|
101
|
-
}
|
102
|
-
|
103
|
-
lws_context_destroy(context);
|
104
|
-
return 0;
|
105
|
-
}
|
package/lib/rew/css/theme.css
DELETED