ferment
Version:
Peer-to-peer audio publishing and streaming application. Like SoundCloud but decentralized. A mashup of ssb, webtorrent and electron.
132 lines (111 loc) • 3.41 kB
JavaScript
var Value = require('@mmckegg/mutant/value')
var Struct = require('@mmckegg/mutant/struct')
var MutantDict = require('@mmckegg/mutant/dict')
var MutantArray = require('@mmckegg/mutant/array')
var MutantSet = require('@mmckegg/mutant/set')
var computed = require('@mmckegg/mutant/computed')
var mlib = require('ssb-msgs')
var watch = require('@mmckegg/mutant/watch')
module.exports = function (id, myId) {
var obj = Struct({
displayNames: SocialValue(),
images: SocialValue(),
descriptions: SocialValue(),
followers: MutantSet(),
following: MutantSet(),
scopes: MutantSet(),
posts: MutantSet(),
likes: MutantSet(),
reposts: MutantDict(),
isPub: Value(false)
})
obj.id = id
obj.self = Assigned(obj, id)
obj.byMe = Assigned(obj, myId)
obj.description = computed([obj.byMe.description, obj.self.description, obj.descriptions], getSocialValue, { nextTick: true })
obj.displayName = computed([obj.byMe.displayName, obj.self.displayName, obj.displayNames], getSocialValue, { nextTick: true })
obj.image = computed([obj.byMe.image, obj.self.image, obj.images], getSocialValue, { nextTick: true })
obj.postCount = computed([obj.posts], (x) => x.length)
obj.updateFrom = updateFrom.bind(null, obj)
obj._type = 'ferment/profile'
// hold the line open
watch(obj.displayName)
return obj
}
function Assigned (profile, id) {
return Struct({
displayName: profile.displayNames.valueBy(id),
description: profile.descriptions.valueBy(id),
image: profile.images.valueBy(id)
})
}
function updateFrom (profile, sourceId, msg) {
var c = msg.value.content
// name: a non-empty string
if (nonEmptyStr(c.name)) {
var safeName = makeNameSafe(c.name)
profile.displayNames.assignValue(sourceId, safeName)
}
// image: link to image
if ('image' in c) {
var imageLink = mlib.link(c.image, 'blob')
if (imageLink) {
profile.images.assignValue(sourceId, imageLink.link)
}
}
if ('description' in c) {
profile.descriptions.assignValue(sourceId, c.description)
}
}
function getSocialValue (assigned, self, all) {
return assigned || self || mostPopular(all)
}
function mostPopular (obj) {
var max = 0
var value = null
for (var k in obj) {
if (obj[k].length > max) {
max = obj[k].length
value = obj[k]
}
}
return value
}
function makeNameSafe (str) {
// TODO: figure out a good white list. Stuff that lets people be
// creative, but doesn't destroy the page layout or anything.
return String(str)
}
function nonEmptyStr (str) {
return (typeof str === 'string' && !!('' + str).trim())
}
function SocialValue () {
var result = MutantDict()
result.assignValue = assignValue.bind(null, result)
result.valueBy = getValueBy.bind(null, result)
return result
}
function assignValue (dict, assignerId, value) {
dict.keys().forEach((v) => {
var current = dict.get(v)
current.delete(assignerId)
if (!current.getLength()) {
dict.delete(v)
}
})
// add new assignment
if (!dict.get(value)) {
dict.put(value, MutantArray())
}
dict.get(value).push(assignerId)
}
function getValueBy (dict, assignerId) {
return computed([dict, assignerId], valueAssignedBy, { nextTick: true })
}
function valueAssignedBy (assignments, id) {
for (var k in assignments) {
if (assignments[k].includes(id)) {
return k
}
}
}