browser_app_base 0.0.5 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3565687a000a2d7a0636d2ac47c09de24d87cfe1554777b58d8f9d9ab494102d
4
- data.tar.gz: a305213755edff63ab70edff0f2011d52c33ee6fd53b9aaddce80865440107c3
3
+ metadata.gz: d8f803f44d98065ce973ec89c418d7d9d8fb75ce8c1f6dc74f8e449681a3a0f5
4
+ data.tar.gz: 0bf164a5280e040b5efa5fe0221ae17f19d77b4569c3c4db5e4893d19a5e0efb
5
5
  SHA512:
6
- metadata.gz: f2f2cb63d6ff01e6bb39731fd36944a8a4ff96c9b5370ed9b386383bc6c67fe55586d1e6f278d8af17713b542079f1850de0afd820c9b78357d7afc4debb63d8
7
- data.tar.gz: 200b7d9a67ef7421f52a2d3887b91d3d9c5ab99eda27ccebbf1725718204d25945bc0f31679811d0d4e959561ebed2906de8b98900c9272f80196b6fa9f7640a
6
+ metadata.gz: 881fd8551b75678a1825a1cb227918f22ce9e6db9377e940bd7b25d04d7827d491c4f42c0c4da372607666533ada91239fb4f79f3792b3252dedf3c589424de4
7
+ data.tar.gz: 1c630a5c7affe753747bc2aee0789b384249676f6a90a036fce54471084e0bf471c2c88bdd701e13851f5f7d33f53e8360a52e6898a29bc09e9f045183791b9d
data/.vscode/launch.json CHANGED
@@ -5,10 +5,16 @@
5
5
  "version": "0.2.0",
6
6
  "configurations": [
7
7
  {
8
- "name": "Debug Local File",
8
+ "name": "Debug create_browser_app.rb",
9
9
  "type": "Ruby",
10
10
  "request": "launch",
11
- "cwd": "${workspaceRoot}/lib/template/",
11
+ "program": "${workspaceRoot}/bin/create_browser_app.rb"
12
+ },
13
+ {
14
+ "name": "Debug start.rb",
15
+ "type": "Ruby",
16
+ "request": "launch",
17
+ "cwd": "${workspaceRoot}/lib/template",
12
18
  "program": "${workspaceRoot}/lib/template/start.rb"
13
19
  }
14
20
  ]
data/README.md CHANGED
@@ -61,6 +61,47 @@ ui application sample
61
61
  $ cd ~/test/
62
62
  $ ruby start.rb
63
63
 
64
+ ## browser setting
65
+
66
+ config/browser.json
67
+ Set the path for your Windows or Linux Chrome browser
68
+
69
+ ```json
70
+ {
71
+ "chrome_win": "start chrome",
72
+ "chrome_linux": "/bin/google-chrome"
73
+ }
74
+ ```
75
+
76
+ ## Send a message from your browser application to your ruby application
77
+
78
+ Use the send_message function
79
+
80
+ main.js sample
81
+ ```javascript
82
+ $("#exec").click(function () {
83
+ send_message("exec:" + $("#upFile").val());
84
+ });
85
+
86
+ ```
87
+
88
+ ## Send a message from the ruby application to the browser application
89
+
90
+ Use the app_send function
91
+
92
+ my_app_sample.rb sample
93
+ ```ruby
94
+ class MyApp < AppMainBase
95
+ def start(argv)
96
+ # popup message
97
+ app_send("popup:message string")
98
+
99
+ # log message
100
+ yield "log message"
101
+ end
102
+ end
103
+ ```
104
+
64
105
  ## Development
65
106
 
66
107
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BrowserAppBase
4
- VERSION = "0.0.5"
4
+ VERSION = "0.0.9"
5
5
  end
@@ -1,50 +1,50 @@
1
- [
2
- {
3
- "name": "name1",
4
- "value": "value1",
5
- "type": "input",
6
- "select": "",
7
- "description": "設定項目1"
8
- },
9
- {
10
- "name": "name2",
11
- "value": true,
12
- "type": "checkbox",
13
- "select": "",
14
- "description": "有効にする場合はチェック"
15
- },
16
- {
17
- "name": "name3",
18
- "value": "1",
19
- "type": "select",
20
- "select": [
21
- "1",
22
- "2",
23
- "3",
24
- "4",
25
- "5"
26
- ],
27
- "description": "選択項目"
28
- },
29
- {
30
- "name": "name4",
31
- "value": "value4",
32
- "type": "input",
33
- "select": "",
34
- "description": "設定項目4"
35
- },
36
- {
37
- "name": "name5",
38
- "value": "value5",
39
- "type": "input",
40
- "select": "",
41
- "description": "設定項目5"
42
- },
43
- {
44
- "name": "name6",
45
- "value": "value6",
46
- "type": "input",
47
- "select": "",
48
- "description": "設定項目6"
49
- }
50
- ]
1
+ [
2
+ {
3
+ "name": "name1",
4
+ "value": "value1",
5
+ "type": "input",
6
+ "select": "",
7
+ "description": "設定項目1"
8
+ },
9
+ {
10
+ "name": "name2",
11
+ "value": true,
12
+ "type": "checkbox",
13
+ "select": "",
14
+ "description": "有効にする場合はチェック"
15
+ },
16
+ {
17
+ "name": "name3",
18
+ "value": "1",
19
+ "type": "select",
20
+ "select": [
21
+ "1",
22
+ "2",
23
+ "3",
24
+ "4",
25
+ "5"
26
+ ],
27
+ "description": "選択項目"
28
+ },
29
+ {
30
+ "name": "name4",
31
+ "value": "value4",
32
+ "type": "input",
33
+ "select": "",
34
+ "description": "設定項目4"
35
+ },
36
+ {
37
+ "name": "name5",
38
+ "value": "value5",
39
+ "type": "input",
40
+ "select": "",
41
+ "description": "設定項目5"
42
+ },
43
+ {
44
+ "name": "name6",
45
+ "value": "value6",
46
+ "type": "input",
47
+ "select": "",
48
+ "description": "設定項目6"
49
+ }
50
+ ]
@@ -30,6 +30,43 @@ get "/config/*.*" do |file, ext|
30
30
  File.read "config/#{file}.#{ext}"
31
31
  end
32
32
 
33
+ post "/history/*.*" do |file, ext|
34
+ content_type "text/json", :charset => "utf-8"
35
+ puts "#{file}.#{ext}"
36
+ p = params[:param1]
37
+ buf = File.read "history/#{file}.#{ext}"
38
+ data = eval(buf)
39
+ if data != nil
40
+ if p != ""
41
+ JSON.generate data.find_all { |d| d =~ Regexp.new(p) }
42
+ else
43
+ JSON.generate data
44
+ end
45
+ end
46
+ end
47
+
48
+ get "/open_dialog" do
49
+ dialog_html = <<'EOS'
50
+ <!DOCTYPE html>
51
+ <html>
52
+ <head>
53
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
54
+ <title>Message Dialog</title>
55
+ <style type="text/css">
56
+ <!--
57
+ body {
58
+ color: #000000;
59
+ background-color: #ffffff;
60
+ overflow: hidden;
61
+ font-size: 12px;
62
+ }
63
+ -->
64
+ </style>
65
+ </head>
66
+ EOS
67
+ dialog_html += "<body>" + params["msg"] + "</body></html>"
68
+ end
69
+
33
70
  map "/search" do
34
71
  run Search
35
72
  end
@@ -52,6 +89,6 @@ configure do
52
89
 
53
90
  end
54
91
 
55
- #\ --port 52538
92
+ #\ --port 61047
56
93
 
57
94
  run Sinatra::Application
@@ -1,15 +1,19 @@
1
1
  body {
2
2
  color: #000000;
3
- background-color: #cac3ec4f;
3
+ background-color: #cac3ec4f;
4
4
  overflow: hidden;
5
+ font-size: 12px;
5
6
  }
6
7
 
7
8
  hr {
8
9
  color: #ffffff;
9
10
  background-color: #000000;
10
- height: 1px; /* 線の太さ */
11
- border: 1px; /* 枠の太さ */
12
- border-style: solid; /* 枠の種類 */
11
+ height: 1px;
12
+ /* 線の太さ */
13
+ border: 1px;
14
+ /* 枠の太さ */
15
+ border-style: solid;
16
+ /* 枠の種類 */
13
17
  }
14
18
 
15
19
  .error {
@@ -18,7 +22,7 @@ hr {
18
22
 
19
23
  .outarea {
20
24
  background-color: #FFFFFF;
21
- margin: 5px;
25
+ margin: 5px;
22
26
  padding: 5px;
23
27
  width: 95vw;
24
28
  height: 50vh;
@@ -27,15 +31,15 @@ hr {
27
31
 
28
32
  .inarea {
29
33
  border: thin solid #000000;
30
- margin: 5px;
34
+ margin: 5px;
31
35
  padding: 5px;
32
36
  width: 95%;
33
37
  }
34
38
 
35
39
  input.long {
36
40
  width: 90%;
37
- background-color: #FAFAFA;
38
- margin: 5px;
41
+ background-color: #FAFAFA;
42
+ margin: 5px;
39
43
  padding: 5px;
40
44
  }
41
45
 
@@ -49,8 +53,8 @@ textarea.long {
49
53
  }
50
54
 
51
55
  .ui-autocomplete {
52
- max-height: 200px;
53
- max-width: 500px;
56
+ max-height: 45vh;
57
+ max-width: 90wh;
54
58
  overflow-y: auto;
55
59
  overflow-x: auto;
56
60
  padding-right: 10px;
@@ -63,11 +67,11 @@ textarea.long {
63
67
  }
64
68
 
65
69
  .ui-dialog {
66
- position: absolute;
67
- top: 0;
68
- left: 0;
69
- padding: .2em;
70
- outline: 0;
70
+ position: absolute;
71
+ top: 0;
72
+ left: 0;
73
+ padding: .2em;
74
+ outline: 0;
71
75
  }
72
76
 
73
77
  .long {
@@ -76,28 +80,36 @@ textarea.long {
76
80
 
77
81
  #setting_dialog {
78
82
  color: #796fe9;
79
- background-color: #000000;
83
+ background-color: #000000;
80
84
  }
81
85
 
82
86
  .setting_name {
83
87
  width: 200px;
84
88
  color: #796fe9;
85
- background-color: #000000;
89
+ background-color: #000000;
86
90
  }
87
91
 
88
92
  .setting_value {
89
93
  width: 300px;
90
94
  color: #796fe9;
91
- background-color: #000000;
95
+ background-color: #000000;
92
96
  }
93
97
 
94
98
  .setting_checkbox {
95
99
  color: #796fe9;
96
- background-color: #000000;
100
+ background-color: #000000;
97
101
  }
98
102
 
99
103
  ul.log {
100
- list-style-type: decimal;
101
- font-size: 10px;
104
+ list-style-type: decimal;
105
+ font-size: 12px;
102
106
  color: #5d0a94;
107
+ }
108
+
109
+ input[type="search"] {
110
+ -webkit-appearance: searchfield;
111
+ }
112
+
113
+ input[type="search"]::-webkit-search-cancel-button {
114
+ -webkit-appearance: searchfield-cancel-button;
103
115
  }
File without changes
@@ -11,12 +11,15 @@
11
11
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
12
12
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
13
13
 
14
- <script src="http://localhost:52538/js/main.js"></script>
15
- <link rel="stylesheet" href="http://localhost:52538/css/index.css" type="text/css">
14
+ <script src="http://localhost:61047/js/main.js"></script>
15
+ <link rel="stylesheet" href="http://localhost:61047/css/index.css" type="text/css">
16
16
  </head>
17
17
 
18
18
  <body>
19
- <h3>サンプル</h3>
19
+ <div id="msg_dialog" style="display:none;">
20
+ <div id="msg_text">message</div>
21
+ </div>
22
+ <h4>RubyAppBase</h4>
20
23
  <hr>
21
24
  <table>
22
25
  <tr>
@@ -40,7 +43,7 @@
40
43
  </div>
41
44
  <table>
42
45
  <tr>
43
- <td class="long"><input class="inarea" type="text" id="upFile" name="upFile"></td>
46
+ <td class="long"><input class="inarea" type="search" id="upFile" name="upFile"></td>
44
47
  <td><input type="button" id="select_file" value="ファイル選択" /></td>
45
48
  </tr>
46
49
  </table>
@@ -50,7 +53,7 @@
50
53
  </div>
51
54
  <table>
52
55
  <tr>
53
- <td class="long"><input class="inarea" type="text" id="upDir" name="upDir"></td>
56
+ <td class="long"><input class="inarea" type="search" id="upDir" name="upDir"></td>
54
57
  <td><input type="button" id="select_dir" value="フォルダ選択" /></td>
55
58
  </tr>
56
59
  </table>
@@ -2,6 +2,50 @@
2
2
 
3
3
  var $ws = null;
4
4
  var $auto_scroll = true;
5
+ var dialog = null;
6
+
7
+ function open_dialog(msg) {
8
+ console.log("msg=" + msg);
9
+ $("#msg_text").html(msg);
10
+ $("#msg_dialog").dialog({
11
+ modal: true
12
+ , show: "slide" //表示時のアニメーション
13
+ , hide: "slide" //閉じた時のアニメーション
14
+ , title: "Message" //ダイアログのタイトル
15
+ , width: 400 //ダイアログの横幅
16
+ , height: 200 //ダイアログの高さ
17
+ , resizable: true //リサイズ可
18
+ , closeOnEscape: false //[ESC]キーで閉じられなくする
19
+ , draggable: true //ダイアログの移動を可に
20
+ , buttons: {
21
+ "OK": function () { //Cancelボタン
22
+ $(this).dialog("close");
23
+ }
24
+ }
25
+ });
26
+ }
27
+
28
+ function open_dialog_org(msg) {
29
+ var top = window.screenTop + 10;
30
+ var left = window.screenLeft + 10;
31
+ if (dialog != null) {
32
+ dialog.close();
33
+ }
34
+ var dialog = window.open(
35
+ "/open_dialog?msg=" + msg,
36
+ "pop",
37
+ "width=300, height=100, left=" + left + ", top=" + top
38
+ );
39
+ console.log("open dialog dialog=" + dialog);
40
+ if (dialog == null) {
41
+ console.log("open dialog retry");
42
+ setTimeout(function () {
43
+ open_dialog(msg);
44
+ }, 1000);
45
+ } else {
46
+ dialog.focus();
47
+ }
48
+ }
5
49
 
6
50
  function server_connect(url) {
7
51
  var ws = new WebSocket(url);
@@ -11,9 +55,18 @@ function server_connect(url) {
11
55
  };
12
56
  ws.onmessage = function (evt) {
13
57
  //alert(evt.data);
58
+
14
59
  if (evt.data.match(/^startup:/)) {
15
60
  file_name = evt.data.replace(/^startup:/, "");
16
- //alert(file_name);
61
+ }
62
+ else if (evt.data.match(/^app_end:normal/)) {
63
+ open_dialog("終了しました");
64
+ }
65
+ else if (evt.data.match(/^app_end:error/)) {
66
+ open_dialog("<font color='red'>エラーが発生しました</font>");
67
+ }
68
+ else if (evt.data.match(/^popup:/)) {
69
+ open_dialog(evt.data.replace(/^popup:/, ""));
17
70
  } else {
18
71
  var log = "<li>" + evt.data + "</li>";
19
72
  $('#log').append(log);
@@ -43,14 +96,14 @@ function autocomp(id, file_kind) {
43
96
  minLength: 0,
44
97
  delay: 0,
45
98
  select: function (event, ui) {
46
- console.log(ui.item.value);
99
+ //console.log(ui.item.value);
47
100
  jQuery("#" + id).val(ui.item.value);
48
101
  //jQuery(this).autocomplete("search", "");
49
102
  $(this).keydown();
50
103
  },
51
104
  source: function (req, resp) {
52
105
  $.ajax({
53
- url: "http://localhost:52538/search?path=" + $("#" + id).val() + "&kind=" + file_kind,
106
+ url: "http://localhost:61047/search?path=" + $("#" + id).val() + "&kind=" + file_kind,
54
107
  type: "GET",
55
108
  cache: false,
56
109
  dataType: "json",
@@ -72,11 +125,44 @@ function autocomp(id, file_kind) {
72
125
  });
73
126
  }
74
127
 
128
+ function autocomp_history(id, file_name) {
129
+ $("#" + id).autocomplete({
130
+ autoFocus: true,
131
+ minLength: 0,
132
+ delay: 0,
133
+ select: function (event, ui) {
134
+ jQuery("#" + id).val(ui.item.value);
135
+ $(this).keydown();
136
+ },
137
+ source: function (req, resp) {
138
+ $.ajax({
139
+ url: "http://localhost:61047/history/" + file_name,
140
+ type: "POST",
141
+ cache: false,
142
+ dataType: "json",
143
+ data: {
144
+ param1: req.term
145
+ },
146
+ success: function (o) {
147
+ resp(o);
148
+ },
149
+ error: function (xhr, ts, err) {
150
+ resp(['']);
151
+ }
152
+ });
153
+
154
+ }
155
+ }).focus(function () {
156
+ $(this).keydown();
157
+ });
158
+ }
159
+
75
160
  function select_file_dialog(search_id, file_kind, dialog_id, select_file, file_name) {
76
161
  $("#" + select_file).click(function () {
77
162
  autocomp(search_id, file_kind);
78
163
  $(".ui-autocomplete").css("z-index", 1000);
79
- $("#" + search_id).val("/");
164
+ console.log("name=" + $("#" + file_name).val());
165
+ $("#" + search_id).val($("#" + file_name).val());
80
166
  $("#" + dialog_id).dialog({
81
167
  modal: true
82
168
  , show: "slide" //表示時のアニメーション
@@ -139,7 +225,7 @@ function setting_dialog(open_id, dialog_id, json_file) {
139
225
  h += "</tr></table>";
140
226
  $("dl#wrap").append(h);
141
227
  } else {
142
- console.log("type=" + s[i].type);
228
+ //console.log("type=" + s[i].type);
143
229
  }
144
230
  }
145
231
  });
@@ -159,7 +245,7 @@ function setting_dialog(open_id, dialog_id, json_file) {
159
245
  var json_data = []
160
246
  $.getJSON(json_file, function (s) {
161
247
  for (var i in s) {
162
- console.log(s[i].name);
248
+ //console.log(s[i].name);
163
249
  if (s[i].type == "input") {
164
250
  var data = {};
165
251
  data["name"] = s[i].name;
@@ -190,7 +276,7 @@ function setting_dialog(open_id, dialog_id, json_file) {
190
276
  data["description"] = s[i].description;
191
277
  json_data.push(data);
192
278
  } else {
193
- console.log("type=" + s[i].type);
279
+ //console.log("type=" + s[i].type);
194
280
  }
195
281
  }
196
282
  $ws.send("setting:" + JSON.stringify(json_data));
@@ -218,24 +304,37 @@ function dispFile() {
218
304
  alert('選択したファイルの値は' + fName + 'です');
219
305
  }
220
306
 
307
+ function openFile(file) {
308
+ $ws.send("openfile:" + file);
309
+ }
310
+
221
311
  // 起動時の処理
222
312
  $(document).ready(function () {
223
- // サーバに接続
224
- server_connect("ws://localhost:52538/wsserver")
313
+
314
+ window.onload = function (e) {
315
+ console.log("onload");
316
+ // サーバに接続
317
+ server_connect("ws://localhost:61047/wsserver")
318
+ }
319
+
225
320
  // ウインドウサイズ
226
321
  var width = 800;
227
322
  var height = 600;
323
+ $(window).resize(function () {
324
+ $(".outarea").height($(window).height() - 220);
325
+ });
228
326
  // ウインドウの位置
229
327
  $(function () {
230
328
  window.resizeTo(width, height);
231
329
  window.moveTo((window.screen.width / 2) - (width / 2), (screen.height / 2) - (height / 2));
232
330
  //window.moveTo(0,0);
331
+ $(".outarea").height($(window).height() - 220);
233
332
  });
234
333
 
235
334
  $('.outarea').scroll(function () {
236
335
  var h = $('.outarea').get(0).scrollHeight - $('.outarea').innerHeight();
237
- console.log("scrollEnd=" + Math.abs($('.outarea').scrollTop() - h));
238
- if (Math.abs($('.outarea').scrollTop() - h) < 5) {
336
+ //console.log("scrollEnd=" + Math.abs($('.outarea').scrollTop() - h));
337
+ if (Math.abs($('.outarea').scrollTop() - h) < 30) {
239
338
  // 最後までスクロールしている
240
339
  // 自動スクロールON
241
340
  $auto_scroll = true;
@@ -262,5 +361,7 @@ $(document).ready(function () {
262
361
 
263
362
  setting_dialog("setting", "setting_dialog", "config/setting.json");
264
363
 
364
+ autocomp_history("upFile", "history.json")
365
+
265
366
  });
266
367
 
@@ -10,8 +10,16 @@ class MyApp < AppMainBase
10
10
  argv.each do |v|
11
11
  yield v if block_given?
12
12
  end
13
+
14
+ # Browserにメッセージ送信
15
+ app_send("popup:start app #{argv[0]}")
16
+
17
+ # 履歴の保存
18
+ add_history("history.json", argv[0])
19
+
13
20
  while true
14
21
  yield Time.now.to_s if block_given?
22
+ puts Time.now.to_s
15
23
  yield @config["name1"]
16
24
  sleep 1
17
25
  break if @abort
@@ -5,6 +5,17 @@ class AppMainBase
5
5
  @aboet = false
6
6
  @exec = false
7
7
  @suspend = false
8
+ @ws = nil
9
+ end
10
+
11
+ def app_send(str)
12
+ if @ws != nil
13
+ @ws.send(str)
14
+ end
15
+ end
16
+
17
+ def set_ws(ws)
18
+ @ws = ws
8
19
  end
9
20
 
10
21
  def set_config(config)
@@ -27,6 +38,21 @@ class AppMainBase
27
38
  def resume()
28
39
  @suspend = false
29
40
  end
41
+
42
+ # 履歴の保存
43
+ def add_history(file, history_data)
44
+ buf = File.read "history/#{file}"
45
+ data = eval(buf)
46
+ if data == nil
47
+ data = []
48
+ end
49
+ if history_data.to_s != ""
50
+ data.prepend history_data
51
+ end
52
+ File.open("history/#{file}", "w") do |f|
53
+ f.write JSON.pretty_generate data.uniq
54
+ end
55
+ end
30
56
  end
31
57
 
32
58
  require "app_load.rb"
@@ -10,6 +10,35 @@ require "kconv"
10
10
  require "json"
11
11
  require "facter"
12
12
 
13
+ # ログ出力
14
+ module Output
15
+ def self.console_and_file(output_file)
16
+ defout = File.new(output_file, "a+")
17
+ class << defout
18
+ alias_method :write_org, :write
19
+
20
+ def puts(str)
21
+ STDOUT.write(str.to_s + "\n")
22
+ self.write_org(str.to_s + "\n")
23
+ self.flush
24
+ end
25
+
26
+ def write(str)
27
+ STDOUT.write(str)
28
+ self.write_org(str)
29
+ self.flush
30
+ end
31
+ end
32
+ $stdout = defout
33
+ end
34
+ end
35
+
36
+ Output.console_and_file("log.txt")
37
+
38
+ # ディレクトリ移動
39
+ dir = File.dirname(File.expand_path(__FILE__))
40
+ FileUtils.cd dir
41
+
13
42
  # 空きポートを取得
14
43
  def get_unused_port
15
44
  s = TCPServer.open(0)
@@ -37,22 +66,41 @@ buf = File.binread("index.html").toutf8
37
66
  buf.gsub!(/localhost:[0-9]+\//, "localhost:#{port}/")
38
67
  File.binwrite("index.html", buf)
39
68
 
40
- Thread.start {
41
- puts "start browser"
42
- json_file = File.dirname(File.expand_path(__FILE__)) + "/config/browser.json"
43
- json = JSON.parse(File.read json_file)
44
- puts json
45
- kernel = Facter.value(:kernel)
46
- if kernel == "windows"
47
- browser = json["chrome_win"]
48
- elsif kernel == "Linux"
49
- browser = json["chrome_linux"]
50
- else
51
- browser = json["chrome_win"]
52
- end
53
- browser += " -app=http://localhost:#{port}"
54
- puts browser
55
- system browser
56
- }
69
+ begin
70
+ Thread.start {
71
+ puts "wait start web server"
72
+ while true
73
+ begin
74
+ s = TCPSocket.open("localhost", port)
75
+ s.close
76
+ break
77
+ rescue
78
+ puts $!
79
+ sleep 0.1
80
+ end
81
+ end
57
82
 
58
- Rack::Server.start
83
+ puts "start browser"
84
+ json_file = File.dirname(File.expand_path(__FILE__)) + "/config/browser.json"
85
+ json = JSON.parse(File.read json_file)
86
+ puts json
87
+ kernel = Facter.value(:kernel)
88
+ if kernel == "windows"
89
+ browser = json["chrome_win"]
90
+ elsif kernel == "Linux"
91
+ browser = json["chrome_linux"]
92
+ else
93
+ browser = json["chrome_win"]
94
+ end
95
+ browser += " -app=http://localhost:#{port}"
96
+ puts browser
97
+ system browser
98
+ }
99
+
100
+ # start web server
101
+ Rack::Server.start
102
+ rescue
103
+ puts $!
104
+ puts $@
105
+ exit
106
+ end
@@ -1,5 +1,7 @@
1
1
  require "./server_app_base"
2
2
  require "json"
3
+ require "cgi"
4
+ require "thread"
3
5
 
4
6
  def config_json_hash(json)
5
7
  config = {}
@@ -9,8 +11,23 @@ def config_json_hash(json)
9
11
  return config
10
12
  end
11
13
 
14
+ $ws_exit_thread = nil
15
+
12
16
  class WsServer < Sinatra::Base
13
- $ws_list = []
17
+ def initialize
18
+ super
19
+ @ws_list = []
20
+ @ws_lock = Mutex.new
21
+ end
22
+
23
+ def ws_send(str)
24
+ @ws_lock.synchronize do
25
+ if @ws_list[0] != nil
26
+ @ws_list[0].send(str)
27
+ end
28
+ end
29
+ end
30
+
14
31
  json_config = nil
15
32
  exec_thread = nil
16
33
  get "" do
@@ -19,8 +36,18 @@ class WsServer < Sinatra::Base
19
36
  else
20
37
  request.websocket do |ws|
21
38
  ws.onopen do
22
- ws.send("startup:#{$startup_file}")
23
- $ws_list << ws
39
+ puts "ws.open"
40
+ @ws_lock.synchronize do
41
+ @ws_list << ws
42
+ $app.set_ws(ws)
43
+ pp "ws=#{ws}"
44
+ end
45
+ ws_send("startup:#{$startup_file}")
46
+ puts "ws_exit_thread=#{$ws_exit_thread}"
47
+ if $ws_exit_thread != nil
48
+ puts "ws_exit_thread kill"
49
+ Thread.kill $ws_exit_thread
50
+ end
24
51
  end
25
52
  ws.onmessage do |msg|
26
53
  puts msg
@@ -31,11 +58,24 @@ class WsServer < Sinatra::Base
31
58
  $app.set_config(json_config)
32
59
  argv = msg.gsub(/^exec:/, "")
33
60
  exec_thread = Thread.new {
34
- $app.start(argv.split(",")) do |out|
35
- ws.send(out)
61
+ begin
62
+ $app.start(argv.split(",")) do |out|
63
+ ws_send(out)
64
+ end
65
+ ws_send("app_end:normal")
66
+ rescue
67
+ puts $!
68
+ puts $@
69
+ puts "app_end:err"
70
+ ws_send("app_end:error")
71
+ ensure
72
+ puts "exit thread"
73
+ exec_thread = nil
36
74
  end
37
- exec_thread = nil
38
75
  }
76
+ else
77
+ puts "app_end:err"
78
+ ws_send("app_end:error")
39
79
  end
40
80
  end
41
81
  if msg =~ /^stop/
@@ -62,24 +102,34 @@ class WsServer < Sinatra::Base
62
102
  json_config = config_json_hash(json)
63
103
  $app.set_config(json_config)
64
104
  end
105
+ if msg =~ /^openfile:/
106
+ file = msg.gsub(/^openfile:/, "")
107
+ Thread.new {
108
+ system "#{json_config["editor"]} #{CGI.unescapeHTML(file)}"
109
+ }
110
+ end
65
111
 
112
+ # アプリケーション終了
66
113
  if msg == "exit"
67
- unless ENV["OCRA"] == "true"
68
- halt
69
- #exit
70
- end
114
+ #halt
115
+ exit
71
116
  end
72
117
  end
118
+
119
+ # close websocket
73
120
  ws.onclose do
74
121
  puts "websocket closed"
75
- $ws_list.delete(ws)
76
- puts $ws_list.size
77
- if $ws_list.size == 0
78
- puts ENV["OCRA"]
79
- unless ENV["OCRA"] == "true"
122
+ @ws_lock.synchronize do
123
+ @ws_list.delete(ws)
124
+ end
125
+ puts @ws_list.size
126
+ if @ws_list.size == 0
127
+ $ws_exit_thread = Thread.start {
128
+ sleep 1
80
129
  #halt
81
130
  exit
82
- end
131
+ }
132
+ puts "ws_exit_thread=#{$ws_exit_thread}"
83
133
  end
84
134
  end
85
135
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: browser_app_base
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - masataka kuwayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-20 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -118,6 +118,7 @@ files:
118
118
  - lib/template/config/browser.json
119
119
  - lib/template/config/setting.json
120
120
  - lib/template/css/index.css
121
+ - lib/template/history/history.json
121
122
  - lib/template/index.html
122
123
  - lib/template/js/main.js
123
124
  - lib/template/my_app_sample.rb