Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added WSF
standalone_websocket
connector, that provides websocket o…
…n top of `standalone` connector.
- Loading branch information
Showing
11 changed files
with
2,033 additions
and
0 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
library/server/ewsgi/connectors/standalone/standalone_websocket-safe.ecf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" encoding="ISO-8859-1"?> | ||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="connector_standalone_websocket" uuid="38E6F413-E001-4774-9B4C-E0C08753D9F7" library_target="connector_standalone_websocket"> | ||
<target name="connector_standalone_websocket"> | ||
<root all_classes="true"/> | ||
<file_rule> | ||
<exclude>/EIFGENs$</exclude> | ||
<exclude>/\.git$</exclude> | ||
<exclude>/\.svn$</exclude> | ||
</file_rule> | ||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional"> | ||
<debug name="dbglog" enabled="true"/> | ||
<assertions precondition="true"/> | ||
</option> | ||
<setting name="concurrency" value="scoop"/> | ||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> | ||
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/> | ||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/> | ||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/> | ||
<library name="httpd" location="lib\httpd\httpd-safe.ecf" readonly="false"/> | ||
<cluster name="src" location=".\src\"> | ||
<cluster name="implementation" location="$|implementation\" hidden="true"/> | ||
</cluster> | ||
</target> | ||
</system> |
25 changes: 25 additions & 0 deletions
25
library/server/wsf/connector/standalone_websocket-safe.ecf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" encoding="ISO-8859-1"?> | ||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_standalone_websocket" uuid="7C83D4B4-39C9-4D27-941B-0F0AAD45122E" library_target="wsf_standalone_websocket"> | ||
<target name="wsf_standalone_websocket"> | ||
<root all_classes="true"/> | ||
<file_rule> | ||
<exclude>/EIFGENs$</exclude> | ||
<exclude>/\.git$</exclude> | ||
<exclude>/\.svn$</exclude> | ||
</file_rule> | ||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional"> | ||
</option> | ||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> | ||
<library name="connector_standalone" location="..\..\ewsgi\connectors\standalone\standalone-safe.ecf"/> | ||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/> | ||
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/> | ||
<library name="error" location="..\..\..\utility\general\error\error-safe.ecf"/> | ||
<library name="ewsgi" location="..\..\ewsgi\ewsgi-safe.ecf"/> | ||
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/> | ||
<library name="httpd" location="..\..\ewsgi\connectors\standalone\lib\httpd\httpd-safe.ecf"/> | ||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/> | ||
<library name="wsf" location="..\wsf-safe.ecf"/> | ||
<library name="wsf_standalone" location="standalone-safe.ecf"/> | ||
<cluster name="wsf_standalone_websocket" location=".\standalone_websocket\" recursive="true"/> | ||
</target> | ||
</system> |
183 changes: 183 additions & 0 deletions
183
library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_event_i.e
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
note | ||
description: "[ | ||
API to perform actions like opening and closing the connection, sending and receiving messages, and listening | ||
for events. | ||
]" | ||
date: "$Date$" | ||
revision: "$Revision$" | ||
|
||
deferred class | ||
WEB_SOCKET_EVENT_I | ||
|
||
inherit | ||
WEB_SOCKET_CONSTANTS | ||
|
||
REFACTORING_HELPER | ||
|
||
feature -- Web Socket Interface | ||
|
||
on_event (conn: HTTPD_STREAM_SOCKET; a_message: detachable READABLE_STRING_8; a_opcode: INTEGER) | ||
-- Called when a frame from the client has been receive | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
local | ||
l_message: READABLE_STRING_8 | ||
do | ||
debug ("ws") | ||
print ("%Non_event (conn, a_message, " + opcode_name (a_opcode) + ")%N") | ||
end | ||
if a_message = Void then | ||
create {STRING} l_message.make_empty | ||
else | ||
l_message := a_message | ||
end | ||
|
||
if a_opcode = Binary_frame then | ||
on_binary (conn, l_message) | ||
elseif a_opcode = Text_frame then | ||
on_text (conn, l_message) | ||
elseif a_opcode = Pong_frame then | ||
on_pong (conn, l_message) | ||
elseif a_opcode = Ping_frame then | ||
on_ping (conn, l_message) | ||
elseif a_opcode = Connection_close_frame then | ||
on_connection_close (conn, "") | ||
else | ||
on_unsupported (conn, l_message, a_opcode) | ||
end | ||
end | ||
|
||
on_open (conn: HTTPD_STREAM_SOCKET) | ||
-- Called after handshake, indicates that a complete WebSocket connection has been established. | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
deferred | ||
end | ||
|
||
on_binary (conn: HTTPD_STREAM_SOCKET; a_message: READABLE_STRING_8) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
deferred | ||
end | ||
|
||
on_pong (conn: HTTPD_STREAM_SOCKET; a_message: READABLE_STRING_8) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
do | ||
-- log ("Its a pong frame") | ||
-- at first we ignore pong | ||
-- FIXME: provide better explanation | ||
end | ||
|
||
on_ping (conn: HTTPD_STREAM_SOCKET; a_message: READABLE_STRING_8) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
do | ||
send (conn, Pong_frame, a_message) | ||
end | ||
|
||
on_text (conn: HTTPD_STREAM_SOCKET; a_message: READABLE_STRING_8) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
deferred | ||
end | ||
|
||
on_unsupported (conn: HTTPD_STREAM_SOCKET; a_message: READABLE_STRING_8; a_opcode: INTEGER) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
do | ||
-- do nothing | ||
end | ||
|
||
on_connection_close (conn: HTTPD_STREAM_SOCKET; a_message: detachable READABLE_STRING_8) | ||
require | ||
conn_attached: conn /= Void | ||
conn_valid: conn.is_open_read and then conn.is_open_write | ||
do | ||
send (conn, Connection_close_frame, "") | ||
end | ||
|
||
on_close (conn: detachable HTTPD_STREAM_SOCKET) | ||
-- Called after the WebSocket connection is closed. | ||
deferred | ||
end | ||
|
||
feature {NONE} -- Implementation | ||
|
||
send (conn: HTTPD_STREAM_SOCKET; a_opcode:INTEGER; a_message: READABLE_STRING_8) | ||
local | ||
i: INTEGER | ||
l_chunk_size: INTEGER | ||
l_chunk: READABLE_STRING_8 | ||
l_header_message: STRING | ||
l_message_count: INTEGER | ||
n: NATURAL_64 | ||
retried: BOOLEAN | ||
do | ||
print (">>do_send (..., "+ opcode_name (a_opcode) +", ..)%N") | ||
if not retried then | ||
create l_header_message.make_empty | ||
l_header_message.append_code ((0x80 | a_opcode).to_natural_32) | ||
l_message_count := a_message.count | ||
n := l_message_count.to_natural_64 | ||
if l_message_count > 0xffff then | ||
--! Improve. this code needs to be checked. | ||
l_header_message.append_code ((0 | 127).to_natural_32) | ||
l_header_message.append_character ((n |>> 56).to_character_8) | ||
l_header_message.append_character ((n |>> 48).to_character_8) | ||
l_header_message.append_character ((n |>> 40).to_character_8) | ||
l_header_message.append_character ((n |>> 32).to_character_8) | ||
l_header_message.append_character ((n |>> 24).to_character_8) | ||
l_header_message.append_character ((n |>> 16).to_character_8) | ||
l_header_message.append_character ((n |>> 8).to_character_8) | ||
l_header_message.append_character ( n.to_character_8) | ||
elseif l_message_count > 125 then | ||
l_header_message.append_code ((0 | 126).to_natural_32) | ||
l_header_message.append_code ((n |>> 8).as_natural_32) | ||
l_header_message.append_character (n.to_character_8) | ||
else | ||
l_header_message.append_code (n.as_natural_32) | ||
end | ||
conn.put_string (l_header_message) | ||
|
||
|
||
l_chunk_size := 16_384 -- 16K | ||
if l_message_count < l_chunk_size then | ||
conn.put_string (a_message) | ||
else | ||
from | ||
i := 0 | ||
until | ||
l_chunk_size = 0 | ||
loop | ||
debug ("ws") | ||
print ("Sending chunk " + (i + 1).out + " -> " + (i + l_chunk_size).out +" / " + l_message_count.out + "%N") | ||
end | ||
l_chunk := a_message.substring (i + 1, l_message_count.min (i + l_chunk_size)) | ||
conn.put_string (l_chunk) | ||
if l_chunk.count < l_chunk_size then | ||
l_chunk_size := 0 | ||
end | ||
i := i + l_chunk_size | ||
end | ||
debug ("ws") | ||
print ("Sending chunk done%N") | ||
end | ||
end | ||
else | ||
-- FIXME: what should be done on rescue? | ||
end | ||
rescue | ||
retried := True | ||
io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", a_message) !%N") | ||
retry | ||
end | ||
|
||
end |
39 changes: 39 additions & 0 deletions
39
library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_message_type.e
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
note | ||
description: "[ | ||
A web socket message has an opcode specifying the type of the message payload. The | ||
opcode consists of the last four bits in the first byte of the frame header. | ||
]" | ||
date: "$Date$" | ||
revision: "$Revision$" | ||
EIS: "name=Data Frame", "src=http://tools.ietf.org/html/rfc6455#section-5.6", "protocol=uri" | ||
EIS: "name=Control Frame", "src=http://tools.ietf.org/html/rfc6455#section-5.5", "protocol=uri" | ||
|
||
class | ||
WEB_SOCKET_MESSAGE_TYPE | ||
|
||
feature -- Data Frames | ||
|
||
Text: INTEGER = 0x1 | ||
-- The data type of the message is text. | ||
|
||
Binary: INTEGER = 0x2 | ||
-- The data type of the message is binary. | ||
|
||
feature -- Control Frames | ||
|
||
Close: INTEGER = 0x8 | ||
-- The client or server is sending a closing | ||
-- handshake to the server or client. | ||
|
||
Ping: INTEGER = 0x9 | ||
-- The client or server sends a ping to the server or client. | ||
|
||
Pong: INTEGER = 0xA | ||
-- The client or server sends a pong to the server or client. | ||
|
||
feature -- Reserverd | ||
|
||
-- Opcodes 0x3-0x7 are reserved for further non-control frames yet to be | ||
-- defined. | ||
|
||
end |
Oops, something went wrong.