Skip to content

Commit

Permalink
refactor(market): removed deprecated version of Proposal class and le…
Browse files Browse the repository at this point in the history
…ft only the new one: OfferProposal

* chore: applied review remarks
* refactor: renamed Proposal to OfferProposal after talking with reqc
* chore: fixed examples

BREAKING CHANGE: The Proposal class is now renamed to OfferProposal
  • Loading branch information
grisha87 authored May 15, 2024
1 parent 804aa66 commit aaa4a3b
Show file tree
Hide file tree
Showing 25 changed files with 437 additions and 582 deletions.
14 changes: 7 additions & 7 deletions examples/market/scan.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* This example demonstrates how to scan the market for proposals
* This example demonstrates how to scan the market for OfferProposals
* Lets learn what is the average start price
* Notice that we don't need to even allocate any budget for this operation
*/
import { GolemNetwork, ProposalNew } from "@golem-sdk/golem-js";
import { GolemNetwork, OfferProposal } from "@golem-sdk/golem-js";

(async () => {
const glm = new GolemNetwork({
Expand All @@ -26,7 +26,7 @@ import { GolemNetwork, ProposalNew } from "@golem-sdk/golem-js";
payerDetails,
);

const offers = new Set<ProposalNew>();
const offers = new Set<OfferProposal>();

console.log("Scanning the market...");
const subscription = glm.market
Expand All @@ -35,12 +35,12 @@ import { GolemNetwork, ProposalNew } from "@golem-sdk/golem-js";
bufferSize: 5,
})
.subscribe({
next: (proposals) => {
console.log("Received a batch of ", proposals.length, " offers...");
proposals.forEach((proposal) => offers.add(proposal));
next: (OfferProposals) => {
console.log("Received a batch of ", OfferProposals.length, " offers...");
OfferProposals.forEach((OfferProposal) => offers.add(OfferProposal));
},
error: (e) => {
console.error("Error while collecting proposals", e);
console.error("Error while collecting OfferProposals", e);
},
});

Expand Down
6 changes: 3 additions & 3 deletions src/agreement/agreement.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Logger, YagnaOptions } from "../shared/utils";
import { MarketApi } from "ya-ts-client";
import { ProposalNew } from "../market";
import { OfferProposal } from "../market";
import { AgreementDTO } from "./service";
import { InvoiceFilter } from "../payment/service";

Expand Down Expand Up @@ -41,7 +41,7 @@ export interface IAgreementApi {
*
* @return An agreement that's in a "Proposal" state (not yet usable for activity creation)
*/
createAgreement(proposal: ProposalNew): Promise<Agreement>;
createAgreement(proposal: OfferProposal): Promise<Agreement>;

/**
* Request creating an agreement from the provided proposal, send it to the Provider and wait for approval
Expand All @@ -50,7 +50,7 @@ export interface IAgreementApi {
*
* @return An agreement that's already in an "Approved" state and can be used to create activities on the Provider
*/
proposeAgreement(proposal: ProposalNew): Promise<Agreement>;
proposeAgreement(proposal: OfferProposal): Promise<Agreement>;

// TODO: Detach return type from ya-ts-client!
getAgreementState(id: string): Promise<MarketApi.AgreementDTO["state"]>;
Expand Down
6 changes: 3 additions & 3 deletions src/agreement/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Bottleneck from "bottleneck";
import { defaultLogger, Logger, sleep, YagnaApi } from "../shared/utils";
import { Agreement, IAgreementApi, LegacyAgreementServiceOptions } from "./agreement";
import { AgreementServiceConfig } from "./config";
import { GolemMarketError, MarketErrorCode, ProposalNew } from "../market";
import { GolemMarketError, MarketErrorCode, OfferProposal } from "../market";

export interface AgreementDTO {
id: string;
Expand All @@ -12,7 +12,7 @@ export interface AgreementDTO {
export class AgreementCandidate {
agreement?: AgreementDTO;

constructor(readonly proposal: ProposalNew) {}
constructor(readonly proposal: OfferProposal) {}
}

export type AgreementSelector = (candidates: AgreementCandidate[]) => Promise<AgreementCandidate>;
Expand Down Expand Up @@ -69,7 +69,7 @@ export class AgreementPoolService {
* Add proposal for create agreement purposes
* @param proposal Proposal
*/
async addProposal(proposal: ProposalNew) {
async addProposal(proposal: OfferProposal) {
// TODO: this.logger.debug(`New proposal added to pool`, { providerName: proposal.provider.name });
this.pool.add(new AgreementCandidate(proposal));
}
Expand Down
4 changes: 2 additions & 2 deletions src/experimental/reputation/system.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProposalFilterNew, ProposalNew } from "../../market";
import { ProposalFilterNew, OfferProposal } from "../../market";
import { AgreementCandidate, AgreementSelector } from "../../agreement";
import { GolemReputationError } from "./error";
import {
Expand Down Expand Up @@ -333,7 +333,7 @@ export class ReputationSystem {
* @param opts
*/
proposalFilter(opts?: ProposalFilterOptions): ProposalFilterNew {
return (proposal: ProposalNew) => {
return (proposal: OfferProposal) => {
// Filter out rejected operators.
const operatorEntry = this.rejectedOperatorsMap.get(proposal.provider.walletAddress);
if (operatorEntry) {
Expand Down
8 changes: 4 additions & 4 deletions src/golem-network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
MarketApi,
MarketModule,
MarketModuleImpl,
ProposalNew,
OfferProposal,
} from "./market";
import { PaymentModule, PaymentModuleImpl, PaymentModuleOptions } from "./payment";
import { ActivityModule, ActivityModuleImpl, IFileServer } from "./activity";
Expand All @@ -22,7 +22,7 @@ import { IAgreementApi } from "./agreement/agreement";
import { AgreementApiAdapter } from "./shared/yagna/adapters/agreement-api-adapter";
import { ProposalRepository } from "./shared/yagna/repository/proposal-repository";
import { CacheService } from "./shared/cache/CacheService";
import { IProposalRepository } from "./market/proposal";
import { IProposalRepository } from "./market/offer-proposal";
import { DemandRepository } from "./shared/yagna/repository/demand-repository";
import { IDemandRepository } from "./market/demand";
import { GftpServerAdapter } from "./shared/storage/GftpServerAdapter";
Expand Down Expand Up @@ -66,7 +66,7 @@ export type GolemServices = {
activityApi: IActivityApi;
agreementApi: IAgreementApi;
marketApi: MarketApi;
proposalCache: CacheService<ProposalNew>;
proposalCache: CacheService<OfferProposal>;
proposalRepository: IProposalRepository;
demandRepository: IDemandRepository;
fileServer: IFileServer;
Expand Down Expand Up @@ -126,7 +126,7 @@ export class GolemNetwork {
this.storageProvider = this.createStorageProvider();

const demandCache = new CacheService<Demand>();
const proposalCache = new CacheService<ProposalNew>();
const proposalCache = new CacheService<OfferProposal>();

const demandRepository = new DemandRepository(this.yagna.market, demandCache);
const proposalRepository = new ProposalRepository(this.yagna.market, proposalCache);
Expand Down
14 changes: 12 additions & 2 deletions src/market/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Observable } from "rxjs";
import { Demand, DemandSpecification } from "./demand";
import YaTsClient from "ya-ts-client";
import { ProposalNew } from "./proposal";
import { OfferProposal } from "./offer-proposal";

export type NewProposalEvent = YaTsClient.MarketApi.ProposalEventDTO;
export type ProposalRejectedEvent = YaTsClient.MarketApi.ProposalRejectedEventDTO;
Expand Down Expand Up @@ -30,5 +30,15 @@ export interface MarketApi {
/**
* Sends a counter-proposal to the given proposal. Returns the newly created counter-proposal.
*/
counterProposal(receivedProposal: ProposalNew, specification: DemandSpecification): Promise<ProposalNew>;
counterProposal(receivedProposal: OfferProposal, specification: DemandSpecification): Promise<void>;

/**
* Sends a "reject" response for the proposal that was received from the Provider as part of the negotiation process
*
* On the protocol level this means that no further counter-proposals will be generated by the Requestor
*
* @param receivedProposal The proposal from the provider
* @param reason User readable reason that should be presented to the Provider
*/
rejectProposal(receivedProposal: OfferProposal, reason: string): Promise<void>;
}
8 changes: 4 additions & 4 deletions src/market/draft-offer-proposal-pool.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { DraftOfferProposalPool } from "./draft-offer-proposal-pool";
import { instance, mock, when } from "@johanblumenberg/ts-mockito";
import { ProposalNew } from "./index";
import { OfferProposal } from "./index";

describe("Draft Offer Proposal Pool", () => {
// GIVEN
const mockProposal = mock(ProposalNew);
const mockProposal = mock(OfferProposal);
// Most of the time we're testing the case when the Proposal is in `Draft` status
when(mockProposal.isDraft()).thenReturn(true);

// NOTE: ts-mockito instance + JS Set.add() doesn't play along, 2x instance(mockProposal) produces "the same" value for (Set.add)

const secondMockProposal = mock(ProposalNew);
const secondMockProposal = mock(OfferProposal);
// Most of the time we're testing the case when the Proposal is in `Draft` status
when(secondMockProposal.isDraft()).thenReturn(true);

Expand Down Expand Up @@ -41,7 +41,7 @@ describe("Draft Offer Proposal Pool", () => {
it("Will throw an error if the proposal is not in Draft state", async () => {
const pool = new DraftOfferProposalPool();

const proposalMock = mock(ProposalNew);
const proposalMock = mock(OfferProposal);
when(proposalMock.isDraft()).thenReturn(false);

expect(() => pool.add(instance(proposalMock))).toThrow("Cannot add a non-draft proposal to the pool");
Expand Down
36 changes: 18 additions & 18 deletions src/market/draft-offer-proposal-pool.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ProposalNew } from "./proposal";
import { OfferProposal } from "./offer-proposal";
import AsyncLock from "async-lock";
import { EventEmitter } from "eventemitter3";
import { GolemMarketError, MarketErrorCode } from "./error";
import { defaultLogger, Logger, sleep } from "../shared/utils";
import { Observable, Subscription } from "rxjs";

export type ProposalSelector = (proposals: ProposalNew[]) => ProposalNew;
export type ProposalValidator = (proposal: ProposalNew) => boolean;
export type ProposalSelector = (proposals: OfferProposal[]) => OfferProposal;
export type ProposalValidator = (proposal: OfferProposal) => boolean;

export interface ProposalPoolOptions {
/**
Expand Down Expand Up @@ -39,10 +39,10 @@ export interface ProposalPoolOptions {
}

export interface ProposalPoolEvents {
added: (proposal: ProposalNew) => void;
removed: (proposal: ProposalNew) => void;
acquired: (proposal: ProposalNew) => void;
released: (proposal: ProposalNew) => void;
added: (proposal: OfferProposal) => void;
removed: (proposal: OfferProposal) => void;
acquired: (proposal: OfferProposal) => void;
released: (proposal: OfferProposal) => void;
cleared: () => void;
}

Expand Down Expand Up @@ -70,20 +70,20 @@ export class DraftOfferProposalPool {
private readonly acquireTimeoutSec: number = 30;

/** {@link ProposalPoolOptions.selectProposal} */
private readonly selectProposal: ProposalSelector = (proposals: ProposalNew[]) => proposals[0];
private readonly selectProposal: ProposalSelector = (proposals: OfferProposal[]) => proposals[0];

/** {@link ProposalPoolOptions.validateProposal} */
private readonly validateProposal: ProposalValidator = (proposal: ProposalNew) => proposal !== undefined;
private readonly validateProposal: ProposalValidator = (proposal: OfferProposal) => proposal !== undefined;

/**
* The proposals that were not yet leased to anyone and are available for lease
*/
private available = new Set<ProposalNew>();
private available = new Set<OfferProposal>();

/**
* The proposal that were already leased to someone and shouldn't be leased again
*/
private leased = new Set<ProposalNew>();
private leased = new Set<OfferProposal>();

public constructor(private options?: ProposalPoolOptions) {
if (options?.selectProposal) {
Expand All @@ -107,7 +107,7 @@ export class DraftOfferProposalPool {
/**
* Pushes the provided proposal to the list of proposals available for lease
*/
public add(proposal: ProposalNew) {
public add(proposal: OfferProposal) {
if (!proposal.isDraft()) {
this.logger.error("Cannot add a non-draft proposal to the pool", { proposalId: proposal.id });
throw new GolemMarketError("Cannot add a non-draft proposal to the pool", MarketErrorCode.InvalidProposal);
Expand All @@ -121,11 +121,11 @@ export class DraftOfferProposalPool {
*
* This method will reject if no suitable proposal will be found within {@link DraftOfferProposalPool.acquireTimeoutSec} seconds.
*/
public acquire(): Promise<ProposalNew> {
public acquire(): Promise<OfferProposal> {
return this.lock.acquire(
"proposal-pool",
async () => {
let proposal: ProposalNew | null = null;
let proposal: OfferProposal | null = null;

while (proposal === null) {
// Try to get one
Expand Down Expand Up @@ -160,7 +160,7 @@ export class DraftOfferProposalPool {
* Validates if the proposal is still usable before putting it back to the list of available ones
* @param proposal
*/
public release(proposal: ProposalNew): Promise<void> {
public release(proposal: OfferProposal): Promise<void> {
return this.lock.acquire("proposal-pool", () => {
this.leased.delete(proposal);

Expand All @@ -173,7 +173,7 @@ export class DraftOfferProposalPool {
});
}

public remove(proposal: ProposalNew): Promise<void> {
public remove(proposal: OfferProposal): Promise<void> {
return this.lock.acquire("proposal-pool", () => {
if (this.leased.has(proposal)) {
this.leased.delete(proposal);
Expand Down Expand Up @@ -236,12 +236,12 @@ export class DraftOfferProposalPool {
});
}

protected removeFromAvailable(proposal: ProposalNew): void {
protected removeFromAvailable(proposal: OfferProposal): void {
this.available.delete(proposal);
this.events.emit("removed", proposal);
}

public readFrom(source: Observable<ProposalNew[]>): Subscription {
public readFrom(source: Observable<OfferProposal[]>): Subscription {
return source.subscribe({
next: (proposalBatch) => proposalBatch.forEach((proposal) => this.add(proposal)),
error: (e) => this.logger.error("Error while collecting proposals", e),
Expand Down
4 changes: 2 additions & 2 deletions src/market/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { ProposalFilterNew } from "./proposal";
export { ProposalFilterNew } from "./offer-proposal";
export { Demand, BasicDemandPropertyConfig, DemandSpecification } from "./demand";
export { Proposal, ProposalNew, ProposalDTO } from "./proposal";
export { OfferProposal, ProposalDTO } from "./offer-proposal";
export * as ProposalFilterFactory from "./strategy";
export { GolemMarketError, MarketErrorCode } from "./error";
export * as MarketHelpers from "./helpers";
Expand Down
Loading

0 comments on commit aaa4a3b

Please sign in to comment.