Skip to content

Instantly share code, notes, and snippets.

@codeOfRobin
Last active March 5, 2018 09:30
Show Gist options
  • Save codeOfRobin/ac059fe09d47c3302ad2c93ff6b382b4 to your computer and use it in GitHub Desktop.
Save codeOfRobin/ac059fe09d47c3302ad2c93ff6b382b4 to your computer and use it in GitHub Desktop.

Hey folks! 👋 Got kind of a gigantic question, so please bear with me

I'm trying to build a "better" client for phoenixframework.org. For those who know how phoenix works, skip the following section

How does phoenix work?

The idea is that if you want access to multiple "events", like conversations on a chat server, you make only one socket connection and it multiplexes them. You do that by telling the server “hey I want to join this channel”.

So now you’re subscribed to that channel, you get events for it.

What do we want?

Most clients handle this process pretty horribly, like the most popular Swift client called Birdsong

import Birdsong

…

// In your view controller / client
let socket = Socket(url: NSURL(string: "http://localhost:4000/socket/websocket")!, params: ["key": "secret"])

…

socket.onConnect = {
    let channel = self.socket.channel("rooms:some-topic", payload: ["user": "spartacus"])
    channel.on("new:msg", callback: { message in
        print("New message: \(message)")
    })

    channel.join()?.receive("ok", callback: { payload in
        print("Successfully joined: \(channel.topic)")
    })

    channel.send("new:msg", payload: ["body": "Hello!"])
        .receive("ok", callback: { response in
            print("Sent a message!")
        })
        .receive("error", callback: { reason in
            print("Message didn't send: \(reason)")
        })

    // Presence support.
    channel.presence.onStateChange = { newState in
        // newState = dict where key = unique ID, value = array of metas.
        print("New presence state: \(newState)")
    }

    channel.presence.onJoin = { id, meta in
        print("Join: user with id \(id) with meta entry: \(meta)")
    }

    channel.presence.onLeave = { id, meta in
        print("Leave: user with id \(id) with meta entry: \(meta)")
    }
}

socket.connect()

so now in various parts of your app you want to subscribe you basically have to do a

if socket.connected {
//do something
} else {
socket.connect(), then do same thing
}

Also, if you make anew Channel object, and try to subscribe on a socket; It actually discards any previous subscriptions 🤬.

Which is really bad. Basically parts of your app would stop responding. The “official” JS SDK doesn’t handle this well either.

So what I want to do is make a “lazy” client preferrably over Rx/just callbacks that lets you just say: socket.subscribeToChannel and it handles the gory details behind the scenes of subscribing to a channel When you subscribe for the first time, it actually creates a subscription. Any subsequent subscriptions get that “cached” channel object and immediately start getting events and as soon as number of subscribers goes down to 0 it automatically unsubscribes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment