Skip to content

Instantly share code, notes, and snippets.

@voided
Created January 16, 2015 23:25
Show Gist options
  • Save voided/00334b0fd2b7a990da00 to your computer and use it in GitHub Desktop.
Save voided/00334b0fd2b7a990da00 to your computer and use it in GitHub Desktop.
hubot skype adapter - with complimentary bad usage of buffers
{Robot, Adapter, TextMessage, EnterMessage, LeaveMessage, Response} = require 'hubot'
SkypeHostServer = require './skypehost'
class SkypeHost extends Adapter
send: (envelope, strings...) ->
@server.sendChat str for str in strings
emote: (envelope, strings...) ->
@server.sendEmote str for str in strings
reply: (envelope, strings...) ->
@send envelope, "#{envelope.user.name}: #{str}" for str in strings
run: ->
@server = new SkypeHostServer 8880
@server.on 'chat', (user, message) =>
console.log user, ':', message
@receive new TextMessage( user, message )
@server.start()
# tell hubot we're ready
@emit 'connected'
exports.use = (robot) ->
new SkypeHost robot
{EventEmitter} = require 'events'
net = require 'net'
BufferCursor = require 'buffercursor'
# helper for reading our encoded strings
BufferCursor::readString = ->
len = @readUInt32LE 4
return @slice( len ).toString( 'utf8' )
BufferCursor::writeString = (string) ->
len = Buffer.byteLength( string, 'utf8' )
@writeUInt32LE len
@write string, len, 'utf8'
class SkypeHostServer extends EventEmitter
constructor: (@port) ->
@server = net.createServer()
@clients = []
start: ->
@server.on 'connection', (client) => @newClient client
@server.listen @port
console.log 'listening on ', @port
sendChat: (message) ->
console.log '<- outgoing: ', message
data = new BufferCursor( new Buffer( Buffer.byteLength( message ) + 4 + 1 ) )
data.writeUInt8 1
data.writeString message
@sendData data
sendEmote: (message) ->
console.log '<- outgoing: *', message
data = new BufferCursor( new Buffer( Buffer.byteLength( message ) + 4 + 1 ) )
data.writeUInt8 2
data.writeString message
@sendData data
sendTopic: (topic) ->
data = new BufferCursor( new Buffer( Buffer.byteLength( message ) + 4 + 1 ) )
data.writeUInt8 3
data.writeString message
@sendData data
sendData: (data) ->
# need to seek to 0 if we want the data copy to work
data.seek 0
packet = new BufferCursor( new Buffer( data.length + 4 ) )
# write packet payload length
packet.writeUInt32LE data.length
# write payload
packet.copy data
# send packet to all our clients
for client in @clients
client.write packet.buffer
newClient: (client) ->
# add our new client to the list
@clients.push client
client.on 'readable', => @readClient client
client.on 'end', =>
# client disconnected, remove from list
@clients.splice @clients.indexOf( client ), 1
console.log @clients
readClient: (client) ->
if not @packetLen
# if we're here, we just finished reading a packet off the stream (or haven't read any packets)
# so lets try reading one
header = client.read 4
if not header
# we have absolutely nothing available in our stream buffer somehow
return
# read the length from the header
@packetLen = header.readUInt32LE 0
# try reading it
payload = client.read @packetLen
if not payload
# we haven't buffered the entire packet yet, we wait
return
# at this point we've read the length and the entire payload off the network
# we'll want to read the next packet length the next time we receive any data
@packetLen = null
@handlePayload new BufferCursor( payload )
# try reading anything else we might have buffered
@readClient client
handlePayload: (payload) ->
type = payload.readUInt8()
data = payload.slice()
switch type
when 1 then @handleChat data
when 2 then @handleEmote data
when 3 then @handleTopic data
handleChat: (data) ->
user = data.readString()
message = data.readString()
@emit 'chat', user, message
handleEmote: (data) ->
user = data.readString()
message = data.readString()
@emit 'emote', user, message
handleTopic: (data) ->
topic = data.readString()
@emit 'topic', topic
module.exports = SkypeHostServer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment