((.on-error websocket) websocket (format #f "not a websocket uri: ~s" uri-or-string))))
((.on-error websocket) websocket (format #f "cannot open websocket in state: ~s" (.state websocket)))))
+(define (subbytevector bv start end)
+ (if (= (bytevector-length bv) end) bv
+ (let* ((length (- end start))
+ (sub (make-bytevector length)))
+ (bytevector-copy! bv start sub 0 length)
+ sub)))
+
+(define* (make-fragmented-frames data #:key (fragment-size (expt 2 15)))
+ (let ((length (if (string? data) (string-length data)
+ (bytevector-length data))))
+ (let loop ((offset 0))
+ (let* ((size (min fragment-size (- length offset)))
+ (end (+ offset size))
+ (final? (= end length))
+ (continuation? (not (zero? offset)))
+ (frame (if (string? data) (make-text-frame (substring data offset end) #:final? final? #:continuation? continuation?)
+ (make-binary-frame (subbytevector data offset end) #:final? final? #:continuation? continuation?))))
+ (if final? (list frame)
+ (cons frame (loop end)))))))
+
(define-method (websocket-send (websocket <websocket>) message data)
(catch #t ; expect: wrong-type-arg (open port), system-error
(lambda _
- (write-frame
- (cond ((string? data)
- (make-text-frame data))
- ((bytevector? data)
- (make-binary-frame data)))
- (.socket websocket)))
+ (let* ((frames (make-fragmented-frames data)))
+ (let loop ((frames frames) (written '(nothing)))
+ (when (pair? frames)
+ (write-frame (car frames) (.socket websocket))
+ (loop (cdr frames) (cons (car frames) written))))))
(lambda (key . args)
(let ((message (format #f "~a: ~s" key args)))
((.on-error websocket) websocket (format #f "send failed: ~s ~a\n" websocket message))
unmasked."
(make-frame #t 'close masking-key bv))
-(define* (make-text-frame text #:optional masking-key)
+(define* (make-text-frame text #:optional masking-key #:key (final? #t) (continuation? #f)) ;; bah: optional
"Return a text data frame containing the string TEXT, masked with MASKING-KEY.
By default, the text is unmasked."
- (make-frame #t 'text masking-key (string->utf8 text)))
+ (make-frame final? (if continuation? 'continuation 'text) masking-key (string->utf8 text)))
-(define* (make-binary-frame bv #:optional masking-key)
+(define* (make-binary-frame bv #:optional masking-key #:key (final? #t) (continuation? #f))
"Return a binary data frame containing the contents of the
bytevector BV, masked with MASKING-KEY. By default, the data is
unmasked."
- (make-frame #t 'binary masking-key bv))
+ (make-frame final? (if continuation? 'continuation 'binary) masking-key bv))
(define (continuation-frame? frame)
"Return #t if FRAME is a continuation frame."