Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fetch specific feed index update #629

Merged
merged 1 commit into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/feed/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { keccak256Hash } from '../utils/hash'
import { serializeBytes } from '../chunk/serialize'
import { Identifier, uploadSingleOwnerChunkData, makeSingleOwnerChunkFromData } from '../chunk/soc'
import { FeedUpdateOptions, fetchFeedUpdate } from '../modules/feed'
import { FeedUpdateOptions, fetchLatestFeedUpdate, FetchFeedUpdateResponse } from '../modules/feed'
import {
REFERENCE_HEX_LENGTH,
Reference,
Expand Down Expand Up @@ -38,6 +38,7 @@ export interface Epoch {
time: number
level: number
}

export type IndexBytes = Bytes<8>
export type Index = number | Epoch | IndexBytes | string

Expand Down Expand Up @@ -110,7 +111,7 @@ export async function findNextIndex(
options?: FeedUpdateOptions,
): Promise<HexString<typeof INDEX_HEX_LENGTH>> {
try {
const feedUpdate = await fetchFeedUpdate(ky, owner, topic, options)
const feedUpdate = await fetchLatestFeedUpdate(ky, owner, topic, options)

return makeHexString(feedUpdate.feedIndexNext, INDEX_HEX_LENGTH)
} catch (e) {
Expand Down Expand Up @@ -165,13 +166,23 @@ export async function downloadFeedUpdate(ky: Ky, owner: EthAddress, topic: Topic
}

export function makeFeedReader(ky: Ky, type: FeedType, topic: Topic, owner: HexEthAddress): FeedReader {
const download = async (options?: FeedUpdateOptions) => fetchFeedUpdate(ky, owner, topic, { ...options, type })

return {
type,
owner,
topic,
download,
async download(options?: FeedUpdateOptions): Promise<FetchFeedUpdateResponse> {
if (!options?.index) {
return fetchLatestFeedUpdate(ky, owner, topic, { ...options, type })
}

const update = await downloadFeedUpdate(ky, hexToBytes(owner), topic, options.index)

return {
reference: bytesToHex(update.reference),
feedIndex: options.index,
feedIndexNext: '',
}
},
}
}

Expand Down
16 changes: 15 additions & 1 deletion src/modules/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,28 @@ export interface FeedUpdateOptions {
* Specifies the start date as unix time stamp
*/
at?: number

/**
* Can be 'epoch' or 'sequence' (default: 'sequence')
*/
type?: FeedType

/**
* Fetch specific previous Feed's update (default fetches latest update)
*/
index?: string
}

interface FeedUpdateHeaders {
/**
* The current feed's index
*/
feedIndex: string

/**
* The feed's index for next update.
* Only set for the latest update. If update is fetched using previous index, then this is an empty string.
*/
feedIndexNext: string
}
export interface FetchFeedUpdateResponse extends ReferenceResponse, FeedUpdateHeaders {}
Expand Down Expand Up @@ -86,7 +100,7 @@ function readFeedUpdateHeaders(headers: Headers): FeedUpdateHeaders {
* @param topic Topic in hex
* @param options Additional options, like index, at, type
*/
export async function fetchFeedUpdate(
export async function fetchLatestFeedUpdate(
ky: Ky,
owner: HexEthAddress,
topic: Topic,
Expand Down
73 changes: 70 additions & 3 deletions test/integration/bee-class.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bee, BeeDebug, Collection, PssSubscription } from '../../src'
import { Bee, BeeDebug, BeeResponseError, Collection, PssSubscription } from '../../src'
import { makeSigner } from '../../src/chunk/signer'
import { makeSOCAddress, uploadSingleOwnerChunkData } from '../../src/chunk/soc'
import { ChunkReference } from '../../src/feed'
Expand Down Expand Up @@ -444,11 +444,12 @@ describe('Bee class', () => {
describe('feeds', () => {
const owner = testIdentity.address
const signer = testIdentity.privateKey
const topic = randomByteArray(32, Date.now())

it(
'feed writer with two updates',
'should write two updates',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes

Expand All @@ -472,9 +473,75 @@ describe('Bee class', () => {
FEED_TIMEOUT,
)

it(
'should get specific feed update',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes

await feed.upload(getPostageBatch(), referenceZero)

const firstLatestUpdate = await feed.download()
expect(firstLatestUpdate.reference).toEqual(bytesToHex(referenceZero))
expect(firstLatestUpdate.feedIndex).toEqual('0000000000000000')

const referenceOne = new Uint8Array([...new Uint8Array([1]), ...new Uint8Array(31)]) as ChunkReference
await feed.upload(getPostageBatch(), referenceOne)

const secondLatestUpdate = await feed.download()
expect(secondLatestUpdate.reference).toEqual(bytesToHex(referenceOne))
expect(secondLatestUpdate.feedIndex).toEqual('0000000000000001')

const referenceTwo = new Uint8Array([
...new Uint8Array([1]),
...new Uint8Array([1]),
...new Uint8Array(30),
]) as ChunkReference
await feed.upload(getPostageBatch(), referenceTwo)

const thirdLatestUpdate = await feed.download()
expect(thirdLatestUpdate.reference).toEqual(bytesToHex(referenceTwo))
expect(thirdLatestUpdate.feedIndex).toEqual('0000000000000002')

const sendBackFetchedUpdate = await feed.download({ index: '0000000000000001' })
expect(sendBackFetchedUpdate.reference).toEqual(bytesToHex(referenceOne))
expect(sendBackFetchedUpdate.feedIndex).toEqual('0000000000000001')
},
FEED_TIMEOUT,
)
it(
'should fail fetching non-existing index',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes
await feed.upload(getPostageBatch(), referenceZero)

const firstLatestUpdate = await feed.download()
expect(firstLatestUpdate.reference).toEqual(bytesToHex(referenceZero))
expect(firstLatestUpdate.feedIndex).toEqual('0000000000000000')

try {
await feed.download({ index: '0000000000000001' })
throw new Error('Should fail')
} catch (err) {
const e = err as BeeResponseError

expect(e.status).toEqual(404)
expect(e.responseBody).toContain('chunk not found')
}
},
FEED_TIMEOUT,
)

it(
'create feeds manifest and retrieve the data',
async () => {
const topic = randomByteArray(32, Date.now())

const directoryStructure: Collection<Uint8Array> = [
{
path: 'index.html',
Expand Down
4 changes: 2 additions & 2 deletions test/integration/feed/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchFeedUpdate } from '../../../src/modules/feed'
import { fetchLatestFeedUpdate } from '../../../src/modules/feed'
import { hexToBytes, makeHexString } from '../../../src/utils/hex'
import { beeKy, ERR_TIMEOUT, getPostageBatch, testIdentity } from '../../utils'
import { ChunkReference, downloadFeedUpdate, findNextIndex, Index, uploadFeedUpdate } from '../../../src/feed'
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('feed', () => {
const uploadedChunk = await uploadChunk(BEE_KY, 0)
await tryUploadFeedUpdate(BEE_KY, signer, topic, 0, uploadedChunk)

const feedUpdate = await fetchFeedUpdate(BEE_KY, owner, topic)
const feedUpdate = await fetchLatestFeedUpdate(BEE_KY, owner, topic)

expect(feedUpdate.feedIndex).toEqual('0000000000000000')
expect(feedUpdate.feedIndexNext).toEqual('0000000000000001')
Expand Down
6 changes: 3 additions & 3 deletions test/integration/modules/feed.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createFeedManifest, fetchFeedUpdate } from '../../../src/modules/feed'
import { createFeedManifest, fetchLatestFeedUpdate } from '../../../src/modules/feed'
import { HexString, hexToBytes, makeHexString } from '../../../src/utils/hex'
import {
beeKy,
Expand Down Expand Up @@ -29,7 +29,7 @@ describe('modules/feed', () => {
'empty feed update',
async () => {
const emptyTopic = '1000000000000000000000000000000000000000000000000000000000000000' as Topic
const feedUpdate = fetchFeedUpdate(BEE_KY, owner, emptyTopic)
const feedUpdate = fetchLatestFeedUpdate(BEE_KY, owner, emptyTopic)

await expect(feedUpdate).rejects.toThrow('Not Found')
},
Expand All @@ -53,7 +53,7 @@ describe('modules/feed', () => {
const socResponse = await uploadSOC(BEE_KY, owner, identifier, signature, socData, getPostageBatch())
expect(socResponse).toBeType('string')

const feedUpdate = await fetchFeedUpdate(BEE_KY, owner, oneUpdateTopic)
const feedUpdate = await fetchLatestFeedUpdate(BEE_KY, owner, oneUpdateTopic)
expect(feedUpdate.reference).toBeType('string')
expect(feedUpdate.feedIndex).toEqual('0000000000000000')
expect(feedUpdate.feedIndexNext).toEqual('0000000000000001')
Expand Down