Browse Source

lightning and likes working, not DRY:needs work

feature/likes-and-lightning
dskvr 2 years ago
parent
commit
d864421625
  1. 68
      src/components/relays/blocks/RelaysResultTable.vue
  2. 44
      src/components/relays/tasks/RefreshTask.vue
  3. 60
      src/components/relays/tasks/RelayOperatorTask.vue
  4. 12
      src/components/relays/tasks/TasksManager.vue
  5. 3
      src/main.js
  6. 51
      src/store/profiles.js
  7. 1
      src/store/relays.js
  8. 10
      src/store/user.js

68
src/components/relays/blocks/RelaysResultTable.vue

@ -27,10 +27,15 @@
</label> </label>
</span> </span>
</th> </th>
<th scope="col" class="relative py-3.5 pl-0 pr-0 sm:pr-0">
<!-- <th scope="col" class="relative py-3.5 pl-0 pr-0 sm:pr-0" v-if="isLoggedIn()"> <code class="text-xs block">Favorite</code>
</th>
<th scope="col" class="relative py-3.5 pl-0 pr-0 sm:pr-0" v-if="isLoggedIn()">
<code class="text-xs block">Upvote</code> <code class="text-xs block">Upvote</code>
</th> --> </th>
<th scope="col" class="relative py-3.5 pl-0 pr-0 sm:pr-0" v-if="isLoggedIn()">
<code class="text-xs block">LN</code>
</th>
<th scope="col" class="hidden md:table-cell lg:table-cell xl:table-cell verified"> <th scope="col" class="hidden md:table-cell lg:table-cell xl:table-cell verified">
<!-- <span class="verified-shape-wrapper"> <!-- <span class="verified-shape-wrapper">
<span class="shape verified"></span> <span class="shape verified"></span>
@ -57,9 +62,6 @@
<code class="text-xs block">Write</code> <code class="text-xs block">Write</code>
<!-- --> <!-- -->
</th> </th>
<th scope="col" class="relative py-3.5 pl-0 pr-0 sm:pr-0">
<code class="text-xs block">Favorite</code>
</th>
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-200 bg-white"> <tbody class="divide-y divide-gray-200 bg-white">
@ -78,13 +80,40 @@
<a :href="`/relay/${relayClean(relay)}`">{{ relay.replace('wss://', '') }}</a> <a :href="`/relay/${relayClean(relay)}`">{{ relay.replace('wss://', '') }}</a>
</td> </td>
<!-- <td class="w-16 fav text-center" v-if="isLoggedIn()"> <td class="w-16 fav text-center">
<a <a
class=" hover:opacity-100 cursor-pointer opacity-20" class="hover:opacity-100 cursor-pointer"
:class="store.relays.isFavorite(relay) ? 'opacity-100' : 'opacity-10'"
@click="store.relays.toggleFavorite(relay)">
</a>
</td>
<td class="w-16 fav text-center" v-if="isLoggedIn()">
<a
v-if="store.relays.hasCanonical(relay)"
class="hover:opacity-100 cursor-pointer "
:class="{
'opacity-20': !store.user.isLiked(relay),
'opacity-100': store.user.isLiked(relay)
}"
@click="likeRelay(relay)"> @click="likeRelay(relay)">
👍 👍
</a> </a>
</td> --> </td>
<td class="w-16 fav text-center" v-if="isLoggedIn()">
<a
v-if="results[relay]?.info?.pubkey && store.profile.hasProfile(results[relay]?.info?.pubkey) && store.profile.hasLud06(results[relay]?.info?.pubkey)"
class="block hover:opacity-100 cursor-pointer opacity-20"
:href="`lightning:${store.profile.getLud06(results[relay]?.info?.pubkey)}`">
<center> <!--when a deprecated element is the only thing that works, the internet is broken.-->
<svg className="h-6 w-6 block w-auto" preserveAspectRatio="xMidYMin" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
<path d="M11.983 1.907a.75.75 0 00-1.292-.657l-8.5 9.5A.75.75 0 002.75 12h6.572l-1.305 6.093a.75.75 0 001.292.657l8.5-9.5A.75.75 0 0017.25 8h-6.572l1.305-6.093z" />
</svg>
</center>
</a>
</td>
<td class="w-12 verified text-center md:table-cell lg:table-cell xl:table-cell"> <td class="w-12 verified text-center md:table-cell lg:table-cell xl:table-cell">
<span v-if="this.results[relay]?.identities"> <span v-if="this.results[relay]?.identities">
@ -119,14 +148,6 @@
<span class="m-auto block" :class="getCheckIndicator(relay, 'write')">&nbsp;</span> <span class="m-auto block" :class="getCheckIndicator(relay, 'write')">&nbsp;</span>
</td> </td>
<td class="w-16 fav text-center">
<a
class="hover:opacity-100 cursor-pointer"
:class="store.relays.isFavorite(relay) ? 'opacity-100' : 'opacity-10'"
@click="store.relays.toggleFavorite(relay)">
</a>
</td>
</tr> </tr>
</tbody> </tbody>
@ -159,17 +180,18 @@
const localMethods = { const localMethods = {
async likeRelay(relay){ async likeRelay(relay){
const like = !this.store.user.isLiked(relay)
const id = this.store.relays.getCanonical(relay) const id = this.store.relays.getCanonical(relay)
const event = { const event = {
created_at: Math.floor(Date.now()/1000), created_at: Math.floor(Date.now()/1000),
kind: 7, kind: 7,
content: '+',
tags: [ tags: [
['e', id], ['e', id],
['p', this.store.user.getPublicKey] ['p', this.store.user.getPublicKey]
], ],
pubkey: this.store.user.getPublicKey pubkey: this.store.user.getPublicKey
} }
event.content = like ? '+' : '-'
event.id = getEventHash(event) event.id = getEventHash(event)
console.log('like event', event) console.log('like event', event)
@ -178,7 +200,15 @@
let ok = validateEvent(signedEvent) let ok = validateEvent(signedEvent)
let veryOk = await verifySignature(signedEvent) let veryOk = await verifySignature(signedEvent)
console.log('valid event?', ok, veryOk) if(!ok || !veryOk)
return
this.$pool.send(['EVENT', signedEvent])
if(like)
this.store.user.like(relay)
else
this.store.user.unlike(relay)
}, },
} }

44
src/components/relays/tasks/RefreshTask.vue

@ -1,29 +1,31 @@
<template> <template>
<span <span
v-if="!store.tasks.isActive || store.tasks.getActiveSlug === this.taskSlug" v-if="!store.tasks.isActive || store.tasks.getActiveSlug === this.taskSlug"
class="text-white lg:text-sm mr-2 ml-2 mt-1.5 text-xs"> class="inline-block mt-0.5">
<span
<span v-if="!store.tasks.isProcessing(this.taskSlug)">Checked {{ sinceLast }} ago</span> class="text-white lg:text-sm mr-2 ml-2 text-xs">
<span v-if="store.tasks.isProcessing(this.taskSlug)" class="italic lg:pr-9">
<svg class="animate-spin mr-1 -mt-0.5 h-4 w-5 text-white inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <span v-if="!store.tasks.isProcessing(this.taskSlug)">Checked {{ sinceLast }} ago</span>
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <span v-if="store.tasks.isProcessing(this.taskSlug)" class="italic lg:pr-9">
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> <svg class="animate-spin mr-1 -mt-0.5 h-4 w-5 text-white inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
</svg> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
{{ this.store.tasks.getProcessed(this.taskSlug).length }}/{{ this.relays.length }} Relays Checked <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
{{ this.store.tasks.getProcessed(this.taskSlug).length }}/{{ this.relays.length }} Relays Checked
</span>
</span> </span>
<span class="text-white text-sm mr-2" v-if="!store.tasks.isProcessing(this.taskSlug)">-</span>
<span class="text-white text-sm mr-2" v-if="store.prefs.refresh && !store.tasks.isProcessing(this.taskSlug)">
Next check in: {{ untilNext }}
</span>
<button
v-if="!store.tasks.isProcessing(this.taskSlug)"
class="mr-8 my-1 py-0 px-3 text-xs rounded border-b-3 border-slate-700 bg-slate-500 font-bold text-white hover:border-slate-500 hover:bg-slate-400"
:disabled='store.tasks.isProcessing(this.taskSlug)'
@click="refreshNow()">
Check{{ relay ? ` ${relay}` : "" }} Now
</button>
</span> </span>
<span class="text-white text-sm mr-2 mt-1.5" v-if="!store.tasks.isProcessing(this.taskSlug)">-</span>
<span class="text-white text-sm mr-2 mt-1.5" v-if="store.prefs.refresh && !store.tasks.isProcessing(this.taskSlug)">
Next check in: {{ untilNext }}
</span>
<button
v-if="!store.tasks.isProcessing(this.taskSlug)"
class="mr-8 my-1 py-0 px-3 text-xs rounded border-b-3 border-slate-700 bg-slate-500 font-bold text-white hover:border-slate-500 hover:bg-slate-400"
:disabled='store.tasks.isProcessing(this.taskSlug)'
@click="refreshNow()">
Check{{ relay ? ` ${relay}` : "" }} Now
</button>
</template> </template>
<style scoped> <style scoped>

60
src/components/relays/tasks/RelayOperatorTask.vue

@ -41,7 +41,12 @@ const localMethods = {
() => { () => {
const relays = this.store.relays.getAggregateCache('public') const relays = this.store.relays.getAggregateCache('public')
console.log('public relays', this.store.relays.getAggregateCache('public').length) if( !relays.length ){
this.store.tasks.completeJob()
return
}
// console.log('public relays', this.store.relays.getAggregateCache('public').length)
const pool = new RelayPool(relays) const pool = new RelayPool(relays)
const subid = crypto.randomBytes(40).toString('hex') const subid = crypto.randomBytes(40).toString('hex')
@ -51,42 +56,60 @@ const localMethods = {
7: new Set(), 7: new Set(),
} }
const limits = { // const limits = {
0: 1, // 0: 1,
1: 20, // 1: 20,
7: 100 // 7: 100
} // }
// const kinds = [0,1,7]
const kinds = [0]
const pubkeys = new Set()
Object.keys(this.results).forEach( relayKey => {
const result = this.results[relayKey]
const pubkey = result?.info?.pubkey
if(!pubkey)
return
pubkeys.add(pubkey)
})
const kinds = [0,1,7]
//remove kind 1 for non-single page tasks //remove kind 1 for non-single page tasks
pool pool
.on('open', relay => { .on('open', relay => {
relay.subscribe(subid, { limit:10, kinds:kinds, authors:[this.result.info.pubkey] }) console.log('subscribing', Array.from(pubkeys) )
relay.subscribe(subid, { limit:pubkeys.size, kinds:kinds, authors: Array.from(pubkeys) })
}) })
.on('event', (relay, sub_id, event) => { .on('event', (relay, sub_id, event) => {
console.log(event)
if(!kinds.includes(event.kind)) if(!kinds.includes(event.kind))
return return
if(sub_id !== subid) if(sub_id !== subid)
return return
const u = uniques[event.kind],
l = limits[event.kind] const u = uniques[event.kind]
if( u.has(event.id) || u.size > l ) // l = limits[event.kind]
if( u.has(event.id) )
return return
if( !(event instanceof Object) ) if( !(event instanceof Object) )
return return
if( !( this.events[event.kind] instanceof Object )) if( !( this.events[event.kind] instanceof Object ))
this.events[event.kind] = new Object() this.events[event.kind] = new Object()
this.events[event.kind][event.id] = event this.events[event.kind][event.id] = event
this.store.profile.setProfile(event.pubkey, JSON.parse(event.content))
u.add(event.id) u.add(event.id)
if(event.kind === 0)
this.store.profile.setProfile(JSON.parse(event.content)).catch()
console.log(`kind: ${event.kind} found`, '... total', u.size, Object.keys(this.events[event.kind]).length)
console.log( 'event!', event.content )
}) })
this.store.tasks.completeJob() setTimeout( () => {
pool.unsubscribe()
pool.close()
this.store.tasks.completeJob()
}, 10000 )
// .on('eose', relay => { // .on('eose', relay => {
// relay.close() // relay.close()
// }) // })
@ -107,7 +130,8 @@ export default defineComponent({
components: {}, components: {},
data() { data() {
return { return {
taskSlug: 'relays/operatorprofiles' taskSlug: 'relays/operatorprofiles',
events: {}
} }
}, },
setup(props){ setup(props){

12
src/components/relays/tasks/TasksManager.vue

@ -1,10 +1,10 @@
<template> <template>
<RefreshTask <RefreshTask
v-bind:resultsProp="results" /> v-bind:resultsProp="results" />
<!-- <RelayCanonicalsTask <RelayCanonicalsTask
:resultsProp="results" /> :resultsProp="results" />
<RelayOperatorTask <RelayOperatorTask
:resultsProp="results" /> --> :resultsProp="results" />
</template> </template>
<script> <script>
@ -16,15 +16,15 @@ import { setupStore } from '@/store'
import SharedComputed from '@/shared/computed.js' import SharedComputed from '@/shared/computed.js'
import RefreshTask from './RefreshTask.vue' import RefreshTask from './RefreshTask.vue'
// import RelayCanonicalsTask from './RelayCanonicalsTask.vue' import RelayCanonicalsTask from './RelayCanonicalsTask.vue'
// import RelayOperatorTask from './RelayOperatorTask.vue' import RelayOperatorTask from './RelayOperatorTask.vue'
export default defineComponent({ export default defineComponent({
name: "TasksManager", name: "TasksManager",
components: { components: {
RefreshTask, RefreshTask,
// RelayCanonicalsTask, RelayCanonicalsTask,
// RelayOperatorTask RelayOperatorTask
}, },
data(){ data(){
return { return {

3
src/main.js

@ -29,7 +29,8 @@ app.config.globalProperties.$tabId = crypto.randomBytes(40).toString('hex')
app.config.globalProperties.$filters = [] app.config.globalProperties.$filters = []
// app.config.globalProperties.$pool = new RelayPool(relays, {reconnect: false}) // app.config.globalProperties.$pool = new RelayPool(relays, {reconnect: false})
app.config.globalProperties.$pool = new RelayPool(['wss://relay.nostr.ch']) app.config.globalProperties.$pool = new RelayPool(['wss://nostr.sandwich.farm'])
app.config.globalProperties.$pool.on('ok', () => console.log('ok') )
await router.isReady() await router.isReady()

51
src/store/profiles.js

@ -1,23 +1,34 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useProfileStore = defineStore('profiles', { export const useProfileStore = defineStore(
state: () => ({ 'profiles',
name: new String(), {
about: new String(), state: () => ({
picture: new String(), data: new Object()
nip05: new String(), }),
lud06: new String(), getters: {
}), getProfiles: (state) => state.data,
getters: {},
actions: { hasProfile: state => pubkey => typeof state.data[pubkey] !== 'undefined',
setProfile(profile){ hasLud06: state => pubkey => typeof state.data[pubkey] !== 'undefined' && typeof state.data[pubkey].lud06 !== 'undefined',
Object.keys(profile).forEach( key => { getProfile: state => pubkey => state.data[pubkey],
if( !(profile[key] instanceof String) ) getLud06: state => pubkey => state.data[pubkey]?.lud06,
return getPicture: state => pubkey => state.data[pubkey]?.picture,
if( !(this[key] instanceof String) ) getName: state => pubkey => state.data[pubkey]?.name,
return getNip05: state => pubkey => state.data[pubkey]?.nip05,
this[key] = profile[key]
})
}, },
}, actions: {
}) setProfile(pubkey, profile){
console.log('setting ', pubkey, profile)
if( !(this.data[pubkey] instanceof Object) )
this.data[pubkey] = new Object()
Object.keys(profile).forEach( key => {
// if( !(profile[key] instanceof String) )
// return
console.log('setting profile', key, profile[key])
this.data[pubkey][key] = profile[key]
})
},
},
}
)

1
src/store/relays.js

@ -51,6 +51,7 @@ export const useRelaysStore = defineStore('relays', {
getCanonicals: state => state.canonicals, getCanonicals: state => state.canonicals,
getCanonical: state => relay => state.canonicals[relay], getCanonical: state => relay => state.canonicals[relay],
hasCanonical: state => relay => typeof state.canonicals[relay] !== 'undefined',
}, },
actions: { actions: {
addRelay(relayUrl){ this.urls.push(relayUrl) }, addRelay(relayUrl){ this.urls.push(relayUrl) },

10
src/store/user.js

@ -5,7 +5,8 @@ export const useUserStore = defineStore('user', {
pubKey: "", pubKey: "",
events: [], events: [],
profile: {}, profile: {},
testEvent: false testEvent: false,
likes: {}
}), }),
getters: { getters: {
getPublicKey: (state) => state.pubKey, getPublicKey: (state) => state.pubKey,
@ -14,9 +15,14 @@ export const useUserStore = defineStore('user', {
getPicture: (state) => state.profile.picture, getPicture: (state) => state.profile.picture,
getNip05: (state) => state.profile.nip05, getNip05: (state) => state.profile.nip05,
isProfile: (state) => Object.keys(state.profile).length ? true : false, isProfile: (state) => Object.keys(state.profile).length ? true : false,
getTestEvent: (state) => state.testEvent getTestEvent: (state) => state.testEvent,
getLikes: state => state.likes,
isLiked: state => relay => state.likes[relay]
}, },
actions: { actions: {
unlike: function(relay){ this.likes[relay] = false },
like: function(relay){ this.likes[relay] = true },
setPublicKey: function(pubKey){ this.pubKey = pubKey }, setPublicKey: function(pubKey){ this.pubKey = pubKey },
setProfile: function(stringifiedEvContent){ setProfile: function(stringifiedEvContent){
this.profile = JSON.parse(stringifiedEvContent) this.profile = JSON.parse(stringifiedEvContent)

Loading…
Cancel
Save