This commit is contained in:
Martti Malmi 2022-12-28 14:37:09 +02:00
parent 6418467887
commit ac507a6f21
5 changed files with 53 additions and 34 deletions

View File

@ -1 +1 @@
src/js/lib/*.js src/js/lib/**

View File

@ -1,9 +1,11 @@
import iris from 'iris-lib'; import iris from 'iris-lib';
import { debounce, throttle } from 'lodash'; import { debounce, throttle } from 'lodash';
import { Event, Filter, getEventHash, Relay, relayInit, signEvent } from './lib/nostr-tools'; import { Event, Filter, getEventHash, Relay, relayInit, signEvent } from './lib/nostr-tools';
const bech32 = require('bech32-buffer'); const bech32 = require('bech32-buffer');
import localForage from 'localforage';
import SortedLimitedEventSet from './SortedLimitedEventSet'; import SortedLimitedEventSet from './SortedLimitedEventSet';
import localForage from "localforage";
function arrayToHex(array: any) { function arrayToHex(array: any) {
return Array.from(array, (byte: any) => { return Array.from(array, (byte: any) => {
@ -33,7 +35,7 @@ const saveLocalStorageProfiles = throttle((profileMap: Map<string, any>) => {
return; return;
} }
// should we save profile events instead? application state would be only changed by events // should we save profile events instead? application state would be only changed by events
const profiles = Array.from(profileMap.keys()).map(pub => { const profiles = Array.from(profileMap.keys()).map((pub) => {
const p = profileMap.get(pub); const p = profileMap.get(pub);
p && (p.pub = pub); p && (p.pub = pub);
return p; return p;
@ -115,11 +117,11 @@ export default {
this.handleEvent(myFollowsEvent as Event); this.handleEvent(myFollowsEvent as Event);
} }
if (Array.isArray(profiles)) { if (Array.isArray(profiles)) {
profiles.forEach(p => p && this.profiles.set(p.pub, p)); profiles.forEach((p) => p && this.profiles.set(p.pub, p));
} }
if (Array.isArray(latestMsgs)) { if (Array.isArray(latestMsgs)) {
console.log('loaded latestmsgs'); console.log('loaded latestmsgs');
latestMsgs.forEach(msg => { latestMsgs.forEach((msg) => {
this.handleEvent(msg); // TODO this does nothing because follows are not known yet this.handleEvent(msg); // TODO this does nothing because follows are not known yet
}); });
} }
@ -226,16 +228,17 @@ export default {
if (_this.subscribedPosts.size === 0) return; if (_this.subscribedPosts.size === 0) return;
console.log('subscribe to posts', Array.from(_this.subscribedPosts)); console.log('subscribe to posts', Array.from(_this.subscribedPosts));
for (const relay of _this.relays.values()) { for (const relay of _this.relays.values()) {
const sub = relay.sub([{ ids: Array.from(_this.subscribedPosts) }], {}); const sub = relay.sub([{ ids: Array.from(_this.subscribedPosts) }], {});
// TODO update relay lastSeen // TODO update relay lastSeen
sub.on('event', (event) => _this.handleEvent(event)); sub.on('event', (event) => _this.handleEvent(event));
} }
}, 1000), }, 1000),
subscribe: function (filters: Filter[], cb: Function | undefined) { subscribe: function (filters: Filter[], cb: Function | undefined) {
cb && this.subscriptions.set(subscriptionId++, { cb &&
filters, this.subscriptions.set(subscriptionId++, {
callback: cb, filters,
}); callback: cb,
});
let hasNewAuthors = false; let hasNewAuthors = false;
let hasNewIds = false; let hasNewIds = false;
@ -320,7 +323,10 @@ export default {
this.directRepliesByMessageId.get(replyingTo)?.add(event.id); this.directRepliesByMessageId.get(replyingTo)?.add(event.id);
// are boost messages screwing this up? // are boost messages screwing this up?
const repliedMsgs = event.tags.filter((tag) => tag[0] === 'e').map(tag => tag[1]).slice(0,2); const repliedMsgs = event.tags
.filter((tag) => tag[0] === 'e')
.map((tag) => tag[1])
.slice(0, 2);
for (const id of repliedMsgs) { for (const id of repliedMsgs) {
if (!this.threadRepliesByMessageId.has(id)) { if (!this.threadRepliesByMessageId.has(id)) {
this.threadRepliesByMessageId.set(id, new Set<string>()); this.threadRepliesByMessageId.set(id, new Set<string>());
@ -531,7 +537,12 @@ export default {
getRepliesAndLikes(id: string, cb: Function | undefined) { getRepliesAndLikes(id: string, cb: Function | undefined) {
const callback = () => { const callback = () => {
cb && cb(this.directRepliesByMessageId.get(id), this.likesByMessageId.get(id), this.threadRepliesByMessageId.get(id)?.size ?? 0); cb &&
cb(
this.directRepliesByMessageId.get(id),
this.likesByMessageId.get(id),
this.threadRepliesByMessageId.get(id)?.size ?? 0,
);
}; };
if (this.directRepliesByMessageId.has(id) || this.likesByMessageId.has(id)) { if (this.directRepliesByMessageId.has(id) || this.likesByMessageId.has(id)) {
callback(); callback();
@ -563,7 +574,8 @@ export default {
} }
return new Promise((resolve) => { return new Promise((resolve) => {
this.subscribe([{ ids: [id] }], () => { // TODO turn off subscription this.subscribe([{ ids: [id] }], () => {
// TODO turn off subscription
resolve(this.messagesById.get(id)); resolve(this.messagesById.get(id));
}); });
}); });

View File

@ -74,7 +74,8 @@ class PublicMessage extends Message {
}; };
}; };
if (Nostr.messagesById.has(nostrId)) { // for faster painting, return synchronously if we have the message if (Nostr.messagesById.has(nostrId)) {
// for faster painting, return synchronously if we have the message
return processNostrMessage(Nostr.messagesById.get(nostrId)); return processNostrMessage(Nostr.messagesById.get(nostrId));
} }
@ -126,7 +127,9 @@ class PublicMessage extends Message {
const nostrId = Nostr.toNostrHexAddress(this.props.hash); const nostrId = Nostr.toNostrHexAddress(this.props.hash);
const msg = r.signedData; const msg = r.signedData;
msg.info = { from: nostrId ? Nostr.toNostrBech32Address(r.signerKeyHash, 'npub') : r.signerKeyHash }; msg.info = {
from: nostrId ? Nostr.toNostrBech32Address(r.signerKeyHash, 'npub') : r.signerKeyHash,
};
if (this.props.filter) { if (this.props.filter) {
if (!this.props.filter(msg)) { if (!this.props.filter(msg)) {
return; return;
@ -156,7 +159,11 @@ class PublicMessage extends Message {
if (nostrId) { if (nostrId) {
Nostr.getRepliesAndLikes(nostrId, (replies, likes, threadReplyCount) => { Nostr.getRepliesAndLikes(nostrId, (replies, likes, threadReplyCount) => {
this.likedBy = new Set(likes); this.likedBy = new Set(likes);
const sortedReplies = replies && Array.from(replies).sort((a, b) => Nostr.messagesById.get(a)?.time - Nostr.messagesById.get(b)?.time); const sortedReplies =
replies &&
Array.from(replies).sort(
(a, b) => Nostr.messagesById.get(a)?.time - Nostr.messagesById.get(b)?.time,
);
this.setState({ this.setState({
likes: this.likedBy.size, likes: this.likedBy.size,
liked: this.likedBy.has(myPub), liked: this.likedBy.has(myPub),
@ -266,16 +273,17 @@ class PublicMessage extends Message {
render() { render() {
const isThumbnail = this.props.thumbnail ? 'thumbnail-item' : ''; const isThumbnail = this.props.thumbnail ? 'thumbnail-item' : '';
if (!this.state.msg) { if (!this.state.msg) {
return html` return html` <div
<div ref=${this.ref} key=${this.props.hash} ref=${this.ref}
key=${this.props.hash}
class="msg ${isThumbnail} ${this.props.asReply ? 'reply' : ''} ${this.props.standalone class="msg ${isThumbnail} ${this.props.asReply ? 'reply' : ''} ${this.props.standalone
? 'standalone' ? 'standalone'
: ''}" : ''}"
> >
<div class="msg-content"> <div class="msg-content">
${this.state.retrieving ? html`<div class="retrieving">Looking up message...</div>` : ''} ${this.state.retrieving ? html`<div class="retrieving">Looking up message...</div>` : ''}
</div> </div>
</div>`; </div>`;
} }
//if (++this.i > 1) console.log(this.i); //if (++this.i > 1) console.log(this.i);
let name = this.props.name || this.state.name || this.shortPubKey(this.state.msg.info.from); let name = this.props.name || this.state.name || this.shortPubKey(this.state.msg.info.from);
@ -405,7 +413,10 @@ class PublicMessage extends Message {
${s.likes || ''} ${s.likes || ''}
</span> </span>
<div class="time"> <div class="time">
<a href="/post/${encodeURIComponent(s.msg.noteId || this.props.hash)}" class="tooltip"> <a
href="/post/${encodeURIComponent(s.msg.noteId || this.props.hash)}"
class="tooltip"
>
${Helpers.getRelativeTimeText(time)} ${Helpers.getRelativeTimeText(time)}
<span class="tooltiptext"> ${dateStr} ${timeStr} </span> <span class="tooltiptext"> ${dateStr} ${timeStr} </span>
</a> </a>

View File

@ -8,10 +8,10 @@ const SafeImg = (props: Props) => {
if (props.src && props.src.indexOf('data:image') !== 0) { if (props.src && props.src.indexOf('data:image') !== 0) {
// free proxy with a 250 images per 10 min limit: https://images.weserv.nl/docs/ // free proxy with a 250 images per 10 min limit: https://images.weserv.nl/docs/
if (props.width) { if (props.width) {
const width = props.width * 2; const width = props.width * 2;
props.src = `https://proxy.irismessengers.wtf/insecure/rs:fill:${width}:${width}/plain/${props.src}`; props.src = `https://proxy.irismessengers.wtf/insecure/rs:fill:${width}:${width}/plain/${props.src}`;
} else { } else {
props.src = `https://proxy.irismessengers.wtf/insecure/plain/${props.src}`; props.src = `https://proxy.irismessengers.wtf/insecure/plain/${props.src}`;
} }
} }
return <img {...props} />; return <img {...props} />;

View File

@ -74,11 +74,7 @@ class Feed extends View {
${s.searchTerm ${s.searchTerm
? '' ? ''
: html` : html`
<${FeedMessageForm} <${FeedMessageForm} key="form${path}" class="hidden-xs" autofocus=${false} />
key="form${path}"
class="hidden-xs"
autofocus=${false}
/>
`} `}
${s.searchTerm ${s.searchTerm
? html`<h2>Search results for "${s.searchTerm}"</h2>` ? html`<h2>Search results for "${s.searchTerm}"</h2>`