Module: WSUI

Defined in:
lib/wsui.rb

Defined Under Namespace

Classes: S

Class Method Summary collapse

Class Method Details

.start(port = 7001, html = "", fps: 5, &block) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/wsui.rb', line 7

def self.start port = 7001, html = "", fps: 5, &block
  app = Module.new do
    @connections = Set.new
    @port = port
    @fps = fps
    @block = block
    def self.call env
      f = lambda do |o|
        if o.is_a? S
          {wsui_id: o.__id__, value: o.value}
        elsif o.respond_to? :each
          o.map &f
        else
          o
        end
      end
      Async::WebSocket::Adapters::Rack.open env, protocols: %w{ ws } do |connection|
        @connections << connection
        while message = connection.read
          if message.key? :id
            t = begin
              ObjectSpace._id2ref message[:id]
            rescue RangeError
              # maybe when we click too fast and the page has 'old' refs
            end
            p t
            t.click&.call t if t.respond_to? :click
          end
          t = f.call(@block.call(message)).to_json
          @connections.each do |connection|
            connection.write t
            connection.flush
          end
        end
      rescue Protocol::WebSocket::ClosedError
        p :closed
      ensure
        @connections.delete connection
      end or [200, [], ["        <html>\n          <head>\n            <meta charset=\"UTF-8\">\n            <script src=\"https://github.com/processing/p5.js/releases/download/v1.4.2/p5.min.js\"></script>\n            <script src=\"https://cdn.jsdelivr.net/gh/abachman/p5.websocket/dist/p5.websocket.min.js\"></script>\n            <script>\n              var all = null;\n              var regions = [];\n              var need = false;   // force draw() on click\n              function setup() {\n                frameRate(\#{@fps});\n                createCanvas(windowWidth, windowHeight);\n                textAlign(CENTER, CENTER);\n                connectWebsocket(\"ws://\" + window.location.host);\n              };\n              function messageReceived(data) {\n                // console.log(data);\n                all = JSON.parse(data);\n                if (need) {\n                  need = false;\n                  draw();\n                }\n              };\n              function draw() {\n                // console.log(all);\n                clear();\n                regions = [];\n                let fv = function(o, left, top, width, height) {\n                  if (o && o.wsui_id) {\n                    regions.push({id: o.wsui_id, left: left, top: top, width: width, height: height});\n                    o = o.value;\n                  };\n                  if (o === null) return;\n                  if (Number.isFinite(o) || typeof o === \"string\" || o instanceof String) {\n                    textSize(min(100, textSize() * min(height / textWidth(\"W\"), width / textWidth(o))));\n                    text(o, left + width / 2, top + height / 2)\n                  } else o.forEach( function(e, i) {\n                    fh(e, left, top + height / o.length * i, width, height / o.length);\n                  } );\n                };\n                let fh = function(o, left, top, width, height) {\n                  if (o && o.wsui_id) {\n                    regions.push({id: o.wsui_id, left: left, top: top, width: width, height: height});\n                    o = o.value;\n                  };\n                  if (o === null) return;\n                  if (Number.isFinite(o) || typeof o === \"string\" || o instanceof String) {\n                    textSize(min(100, textSize() * min(height / textWidth(\"W\"), width / textWidth(o))));\n                    text(o, left + width / 2, top + height / 2)\n                  } else o.forEach( function(e, i) {\n                    fv(e, left + width / o.length * i, top, width / o.length, height);\n                  } );\n                };\n                fv(all, 0, 0, windowWidth, windowHeight);\n                sendMessage({});\n              };\n              function mouseClicked() {\n                regions.some( function(e) {\n                  if (mouseX >= e.left && mouseX <= e.left + e.width && mouseY >= e.top && mouseY <= e.top + e.height) {\n                    sendMessage({id: e.id});\n                    need = true;\n                    return true;\n                  };\n                } );\n              };\n            </script>\n          </head>\n          <body style=\"margin:0\"><main></main></body>\n        </html>\n      HEREDOC\n    end\n  end\n  Thread.new do\n    Async do\n      Falcon::Server.new(\n        Falcon::Server.middleware(app),\n        Async::HTTP::Endpoint.parse(\"http://0.0.0.0:\#{port}\")\n      ).run\n    end\n  end\nend\n"]]