(index ("current-websocket" 0) ("ping-interval" 280) ("close-timeout" 1072) ("connection-timeout" 1347) ("accept-connection" 1760) ("access-denied" 2279) ("drop-incoming-pings" 2589) ("propagate-common-errors" 2897) ("max-frame-size" 4030) ("max-message-size" 4453) ("with-websocket" 4912) ("with-concurrent-websocket" 5944) ("receive-message" 6880) ("send-message" 8945))
(def (sig (parameter "(current-websocket [websocket])" (id current-websocket))) (p (tt "(current-websocket)") " will be bound to a websocket object. Many procedures provide an optional argument for a websocket object and it is bound to " (tt "current-websocket") " by default."))
(def (sig (parameter "(ping-interval [number])" (id ping-interval))) (p "How often to ping the client, in seconds, in the background. If " (tt "0") " then automatic pinging will be disabled. This defaults to 15 seconds.") (p "If this is set to a value greater than 0 then a thread will run in the background sending ping messages to the client at the specified interval. This is used to keep connections open that will otherwise be closed. Often connections without a transmission will be killed after awhile. Receiving pongs in response to a ping will also reset the connection close timer.") (p "pong responses to ping messages are not passed through to the user but they are used to update the timestamp that the connection timeout thread uses to decide if it should kill a connection."))
(def (sig (parameter "(close-timeout [number])" (id close-timeout))) (p "How long to wait, in seconds, for the client to respond to a connection close request before timing out. If " (tt "0") " then the connection timeout will be disabled. The default value is 5 seconds."))
(def (sig (parameter "(connection-timeout [number])" (id connection-timeout))) (p "The length of time in seconds without a response (of any kind) from the client before the connection to the client will be cut off. If " (tt "0") " then the connection will never be timed out by the websocket (something else can, of course, timeout causing the websocket connection to fail anyways). The default is 60 seconds."))
(def (sig (parameter "(accept-connection [procedure])" (id accept-connection))) (p "A one-argument procedure taking as argument the URL path of the current page which tells whether to accept the websocket connection. If " (tt "#t") " accept, " (tt "#f") " reject. " (b "IT IS HIGHLY RECOMMENDED") " that this parameter be set otherwise it opens up your application to potential security vulnerabilities. You will probably want to verify it is coming from a specific source. The default is to accept all connections."))
(def (sig (parameter "(access-denied [procedure])" (id access-denied))) (p "A procedure to be called when the " (tt "origin") " header value is rejected by the " (tt "accept-connection") " procedure.") (p "The default is:") (highlight scheme "(lambda () (send-status 'forbidden \"<h1>Access denied</h1>\"))"))
(def (sig (parameter "(drop-incoming-pings [boolean])" (id drop-incoming-pings))) (p "Clients should usually not initiate pings so the default is to drop all incoming pings without responding with a pong. This defaults to " (tt "#t") ". Set this to " (tt "#f") " to respond to incoming pings with a pong."))
(def (sig (parameter "(propagate-common-errors [boolean])" (id propagate-common-errors))) (p "A lot of errors that occur in the lifecycle of a websocket connection are more-or-less expected and it often is not interesting to receive and deal with these errors. The default is to correctly close the connection when an error occurs with the required opcode but the error is then not signaled to the user. The default is " (tt "#f") ". Set to " (tt "#t") " to receive all errors.") (p "All websocket specific errors are covered by this. The only error you may receive if this is " (tt "#f") " is of type " (tt "websocket") " and " (tt "unexpected-error") " if something goes terribly wrong with the implementation and usually means there is a bug in the implementation. This does not affect errors that are caused by user code, they will always be passed on but the websocket will be properly with an error code of 1011 (unexpected-error).") (p "Note that this parameter is only relevant when using " (tt "with-websocket") " or " (tt "with-concurrent-websocket") ". If you don't use one of those then all errors will be propagated."))
(def (sig (parameter "(max-frame-size [number])" (id max-frame-size))) (p "The maximum allowed frame payload size. The default is " (tt "1MiB") ". If a frame exceeds this size then its payload will not be read and the connection will be dropped immediately. This signals a " (tt "message-too-large") " error.") (p "The maximum frame size supported by the current " (tt "websockets") " implementation is " (tt "1GiB") "."))
(def (sig (parameter "(max-message-size [number])" (id max-message-size))) (p "The maximum allowed total message size. The default is " (tt "1MiB") ". If a frame will cause the " (tt "max-message-size") " to be exceeded then its payload is not read and the connection is dropped immediately. This signals a " (tt "message-too-large") " error.") (p "The maximum message size supported by the current " (tt "websockets") " implementation is " (tt "1GiB") "."))
(def (sig (procedure "(with-websocket [procedure])" (id with-websocket))) (p (tt "with-websocket") " handles the process of setting up and closing off a websocket connection. " (tt "procedure") " is a thunk to be executed after the websocket has been successfully setup. When you use " (tt "with-websocket") " you can be assured that the connection will always be closed correctly even if errors occur in your application code and for all protocol violations.") (p (tt "with-websocket") " sends and receives all messages in a blocking fashion. Only one message will be sent or received at a time unless more threads are introduced in " (tt "procedure") ". Even then the processing will block sending and receiving whereas it will not with " (tt "with-concurrent-websocket") ".") (p "Unless you expect a high volume of messages or messages of very large size on one websocket connection then this is the recommended procedure to use. It is easier to program when you know messages will arrive in order and it is more lightweight."))
(def (sig (procedure "(with-concurrent-websocket [procedure])" (id with-concurrent-websocket))) (p "This will, like " (tt "with-websocket") ", handle setting up and closing a websocket connection. " (tt "procedure") " is a thunk to be executed after the websocket has been successfully setup.") (p (tt "with-concurrent-websocket") " adds to " (tt "with-websocket") " by running a thread in the background to read in messages as they arrive and spins off a new thread to process each message. Messages can arrive out-of-order, especially if there are a mix of very large and very small messages. " (tt "with-concurrent-websocket") " can be very useful if very large messages are expected since they can take a long time to unmask and UTF8 validate.") (p "Sending messages are still done in a blocking fashion but sending is relatively fast and will likely not be a problem. This could change in the future though so don't rely on it."))
(def (sig (procedure "(receive-message #!optional (ws (current-websocket)))" (id receive-message))) (p "Read in a message from the client. Returns two values. The first is the message and the second is the message type, either " (tt "'text") " or " (tt "'binary") ". Regardless of the message type the message itself will always be a string. Takes an optional " (tt "websocket") " object that is bound to " (tt "(current-websocket)") " by default. It will always block until a message is received but if used within " (tt "with-concurrent-websocket") " it will not block other messages from being received or processed and will return the first message that is finished being processed.") (p (tt "receive-message") " is \"concurrent\" aware so if it is used within " (tt "with-websocket") " it will behave in a purely blocking fashion and when used within " (tt "with-concurrent-websocket") " it will utilize the provided concurrency mechanism internally.") (p "Note on performance: the websocket protocol requires all messages to be valid UTF8. The current validation process is extremely fast and generates very little garbage for UTF8 messages that only contain ASCII code points (chars less than 128), but is quite slow and uses a lot of memory when it contains higher plane code points. If you are processing a high volume of messages or exceptionally large messages it may be worthwhile to try to keep all or most messages ASCII only.") (p "This method is thread safe.") (p "A list of the possible message types (symbols):") (ul (li (tt "'text")) (li (tt "'binary")) (li (tt "'connection-close"))) (p "If a message is of type " (tt "binary") " then converting it to something possibly more \"binary\" like, such as a u8vector, could be done with the following. It will incur one copy of the data though.") (highlight scheme "(blob->u8vector/shared (string->blob msg))") (p "You could also use a string port to read the data in different fashions.") (highlight scheme "(with-input-from-string msg\n  (lambda ()\n    (read-byte)\n    (read-u8vector))) ; etc"))
(def (sig (procedure "(send-message data #!optional (message-type 'text) (ws (current-websocket)))" (id send-message))) (p "Send a message to the client. " (tt "data") " is a string or u8vector to be sent to the client. " (tt "message-type") " is one of the types listed under the " (tt "message-types") " section and defaults to " (tt "'text") ". Usually this will be " (tt "'text") " or " (tt "'binary") " but any valid type is allowed. Note that if the " (tt "data") " argument is a u8vector it must be copied before being sent due to some CHICKEN internal limitations, strings will not be. " (tt "send-message") " also takes an optional " (tt "websocket") " object that is bound to " (tt "(current-websocket)") " by default.") (p "This method is thread safe.") (p "A list of the possible message types (symbols):") (ul (li (tt "'text")) (li (tt "'binary")) (li (tt "'ping"))))
