Advertisement
Guest User

Untitled

a guest
Jun 30th, 2018
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 5.01 KB | None | 0 0
  1. #lang racket
  2. (require json)
  3. (require net/http-client)
  4. (require net/url)
  5. (require net/rfc6455)
  6.  
  7. (define config (string->jsexpr (file->string "config.json")))
  8.  
  9. (define (get-gateway-url)
  10.   (define-values (http-response http-headers input)
  11.     (http-sendrecv "discordapp.com" "/api/gateway" #:ssl? #t #:version "1.1" #:method "GET"))
  12.   (combine-url/relative (string->url (hash-ref (read-json input) 'url)) "/"))
  13.  
  14. (define gateway-url (get-gateway-url))
  15.  
  16. (define ws (ws-connect gateway-url))
  17.  
  18. (define last-seq null)
  19.  
  20. (define heartbeat-thread
  21.   (thread
  22.    (lambda ()
  23.      (let loop [(interval null)]
  24.        (cond [(null? interval) (sleep 0.1)
  25.                                (loop (thread-receive))]
  26.              [(number? interval) (sleep (/ interval 1000))
  27.                                  (println "Sending heartbeat!")
  28.                                  (ws-send! ws (jsexpr->string (hasheq 'op 1
  29.                                                                       'd last-seq)))
  30.                                  (loop (let [(msg (thread-try-receive))]
  31.                                          (if msg (loop msg) (loop interval))))])))))
  32.  
  33. (define (send-message-with-file! content file-path channel-id)
  34.   (println (string-append "https://www.rateless.net/~dormo/emotes/" (path->string file-path)))
  35.   (http-sendrecv "discordapp.com"
  36.                  (string-append "/api/channels/" channel-id "/messages")
  37.                  #:ssl? #t
  38.                  #:version "1.1"
  39.                  #:method "POST"
  40.                  #:headers (list (string-append "Authorization: Bot " (hash-ref config 'token))
  41.                                  "User-Agent: RatelessBot (https://rateless.net, v0.1)"
  42.                                  "Content-Type: application/json")
  43.                  #:data (jsexpr->string (hasheq 'content content
  44.                                                 'embed (hasheq 'image (hasheq 'url (string-append "https://www.rateless.net/~dormo/emotes/" (path->string file-path))))
  45.                                                 'nonce (number->string (current-inexact-milliseconds))
  46.                                                 'tts #f))))
  47.  
  48. (define (send-message! content channel-id)
  49.   (http-sendrecv "discordapp.com"
  50.                  (string-append "/api/channels/" channel-id "/messages")
  51.                  #:ssl? #t
  52.                  #:version "1.1"
  53.                  #:method "POST"
  54.                  #:headers (list (string-append "Authorization: Bot " (hash-ref config 'token))
  55.                                  "User-Agent: RatelessBot (https://rateless.net, v0.1)"
  56.                                  "Content-Type: application/json")
  57.                  #:data (jsexpr->string (hasheq 'content content
  58.                                                 'nonce (number->string (current-inexact-milliseconds))
  59.                                                 'tts #f))))
  60.  
  61. (define (handle-event res)
  62.   (cond [(string=? "MESSAGE_CREATE" (hash-ref res 't))
  63.          (cond [(string=? "." (substring (hash-ref (hash-ref res 'd) 'content) 0 1))
  64.                 (let* [(channel-id (hash-ref (hash-ref res 'd) 'channel_id))
  65.                        (emote-name (substring (hash-ref (hash-ref res 'd) 'content) 1 (string-length (hash-ref (hash-ref res 'd) 'content))))
  66.                        (files (filter (lambda (x) (string=? (path->string (path-replace-extension x "")) emote-name)) (directory-list "emotes/")))]
  67.                   (if (< 0 (length files))
  68.                     (send-message-with-file! (substring (hash-ref (hash-ref res 'd) 'content) 1 (string-length (hash-ref (hash-ref res 'd) 'content)))
  69.                                              (first files)
  70.                                              channel-id)
  71.                     (send-message! "That emote doesn't exist" channel-id)))])]))
  72.  
  73. (define (route res)
  74.   (set! last-seq (hash-ref res 's))
  75.   (cond [(= 10 (hash-ref res 'op)) (ws-send! ws
  76.                                              (jsexpr->string (hasheq 'op 2
  77.                                                                      'd (hasheq 'token (hash-ref config 'token)
  78.                                                                                 'properties (hasheq)
  79.                                                                                 'compress #f
  80.                                                                                 'large_threshold 250))))
  81.                                    (thread-send heartbeat-thread (hash-ref (hash-ref res 'd) 'heartbeat_interval))]
  82.         [(= 0 (hash-ref res 'op)) (set! last-seq (hash-ref res 's))
  83.                                   (handle-event res)]))
  84.  
  85. (define ws-listener-thread
  86.   (thread
  87.    (lambda ()
  88.      (let loop ()
  89.        (let ([m (ws-recv ws)])
  90.          (cond [(not (eof-object? m)) (route (string->jsexpr m))]))
  91.        (sleep 0.1) (loop)))))
  92.  
  93. ; TODO:
  94. ; 1. If a client does not receive a heartbeat ack between its attempts at sending heartbeats,
  95. ; it should immediately terminate the connection with a non-1000 close code,
  96. ; reconnect, and attempt to resume.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement