Skip to content

Instantly share code, notes, and snippets.

@carsonfarmer
Created September 5, 2018 22:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carsonfarmer/6377568ccb716494f3d94ed2adc9c77d to your computer and use it in GitHub Desktop.
Save carsonfarmer/6377568ccb716494f3d94ed2adc9c77d to your computer and use it in GitHub Desktop.
Secondary State of Chat Dapp
import 'babel-polyfill'
import Room from 'ipfs-pubsub-room'
import IPFS from 'ipfs'
import ko from 'knockout'
import queryString from 'query-string'
// Global references for demo purposes
let ipfs
let viewModel
const setup = async () => {
// Create view model with properties to control chat
function ViewModel() {
let self = this
// Stores username
self.name = ko.observable('')
// Stores current message
self.message = ko.observable('')
// Stores array of messages
self.messages = ko.observableArray([])
// Stores local peer id
self.id = ko.observable(null)
// Stores whether we've successfully subscribed to the room
self.subscribed = ko.observable(false)
// Logs latest error (just there in case we want it)
self.error = ko.observable(null)
// We compute the ipns link on the fly from the peer id
self.url = ko.pureComputed(() => {
return `https://ipfs.io/ipns/${self.id()}`
})
}
// Create default view model used for binding ui elements etc.
viewModel = new ViewModel()
// Apply default bindings
ko.applyBindings(viewModel)
window.viewModel = viewModel // Just for demo purposes later!
try {
ipfs = new IPFS({
// We need to enable pubsub...
EXPERIMENTAL: {
pubsub: true
},
config: {
Addresses: {
// ...And supply swarm address to announce on
Swarm: [
'/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star'
]
}
}
})
} catch(err) {
console.error('Failed to initialize peer', err)
viewModel.error(err) // Log error...
}
try {
ipfs.on('ready', async () => {
const id = await ipfs.id()
// Update view model
viewModel.id(id.id)
// Can also use query string to specify, see github example
const roomID = "test-room-1234"
// Create basic room for given room id
const room = Room(ipfs, roomID)
// Once the peer has subscribed to the room, we enable chat,
// which is bound to the view model's subscribe
room.on('subscribed', () => {
// Update view model
viewModel.subscribed(true)
})
// When we receive a message...
room.on('message', (msg) => {
const data = JSON.parse(msg.data) // Parse data (which is JSON)
// Update msg name (default to anonymous)
msg.name = data.name ? data.name : "anonymous"
// Update msg text (just for simplicity later)
msg.text = data.text
// Add this to _front_ of array to keep at bottom
viewModel.messages.unshift(msg)
})
// Subscribe to message changes on our view model, likely the result
// of user interaction
viewModel.message.subscribe(async (text) => {
// If not actually subscribed or no text, skip out
if (!viewModel.subscribed() || !text) return
try {
// Get current name
const name = viewModel.name()
// Get current message (one that initiated this update)
const msg = viewModel.message()
// Broadcast message to entire room as JSON string
room.broadcast(Buffer.from(JSON.stringify({ name, text })))
} catch(err) {
console.error('Failed to publish message', err)
viewModel.error(err)
}
// Empty message in view model
viewModel.message('')
})
// Leave the room when we unload
window.addEventListener('unload', async () => await room.leave())
})
} catch(err) {
console.error('Failed to setup chat room', err)
viewModel.error(err)
}
console.log("Ready for chat!")
}
setup()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment