2023-01-02 13:14:32 -06:00
|
|
|
import { Action } from './action.js';
|
2022-12-31 16:08:42 -06:00
|
|
|
import { Actor } from './actor.js';
|
2023-01-26 10:44:57 -06:00
|
|
|
import { CryptoUtil } from './crypto.js';
|
2022-12-31 16:08:42 -06:00
|
|
|
|
2023-01-01 21:09:02 -06:00
|
|
|
class Worker {
|
2023-01-26 10:44:57 -06:00
|
|
|
constructor(reputationPublicKey, tokenId, stakeAmount, duration) {
|
|
|
|
this.reputationPublicKey = reputationPublicKey;
|
2023-01-18 01:07:10 -06:00
|
|
|
this.tokenId = tokenId;
|
2023-01-26 10:44:57 -06:00
|
|
|
this.stakeAmount = stakeAmount;
|
|
|
|
this.duration = duration;
|
2023-01-18 01:07:10 -06:00
|
|
|
this.available = true;
|
|
|
|
this.assignedRequestId = null;
|
2023-01-01 21:09:02 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-31 16:08:42 -06:00
|
|
|
/**
|
|
|
|
* Purpose: Enable staking reputation to enter the pool of workers
|
|
|
|
*/
|
2023-01-01 21:09:02 -06:00
|
|
|
export class Availability extends Actor {
|
2023-02-01 21:43:47 -06:00
|
|
|
constructor(dao, name) {
|
|
|
|
super(name);
|
|
|
|
this.dao = dao;
|
2023-01-02 13:14:32 -06:00
|
|
|
|
|
|
|
this.actions = {
|
2023-02-01 21:43:47 -06:00
|
|
|
assignWork: new Action('assign work'),
|
2023-01-02 13:14:32 -06:00
|
|
|
};
|
2023-01-01 21:09:02 -06:00
|
|
|
|
2023-01-26 10:44:57 -06:00
|
|
|
this.workers = new Map();
|
2023-01-01 21:09:02 -06:00
|
|
|
}
|
|
|
|
|
2023-01-26 10:44:57 -06:00
|
|
|
register(reputationPublicKey, { stakeAmount, tokenId, duration }) {
|
|
|
|
// TODO: Should be signed by token owner
|
2023-02-01 21:43:47 -06:00
|
|
|
this.dao.reputation.lock(tokenId, stakeAmount, duration);
|
2023-01-26 10:44:57 -06:00
|
|
|
const workerId = CryptoUtil.randomUUID();
|
|
|
|
this.workers.set(workerId, new Worker(reputationPublicKey, tokenId, stakeAmount, duration));
|
|
|
|
return workerId;
|
|
|
|
}
|
2023-01-05 01:19:14 -06:00
|
|
|
|
2023-01-01 21:09:02 -06:00
|
|
|
get availableWorkers() {
|
|
|
|
return Array.from(this.workers.values()).filter(({ available }) => !!available);
|
|
|
|
}
|
|
|
|
|
|
|
|
async assignWork(requestId) {
|
2023-01-26 10:44:57 -06:00
|
|
|
const totalAmountStaked = this.availableWorkers
|
|
|
|
.reduce((total, { stakeAmount }) => total += stakeAmount, 0);
|
|
|
|
// Imagine all these amounts layed end-to-end along a number line.
|
|
|
|
// To weight choice by amount staked, pick a stake by choosing a number at random
|
|
|
|
// from within that line segment.
|
|
|
|
const randomChoice = Math.random() * totalAmountStaked;
|
|
|
|
let index = 0;
|
|
|
|
let acc = 0;
|
|
|
|
for (const { stakeAmount } of this.workers.values()) {
|
|
|
|
acc += stakeAmount;
|
|
|
|
if (acc >= randomChoice) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
index += 1;
|
|
|
|
}
|
2023-01-01 21:09:02 -06:00
|
|
|
const worker = this.availableWorkers[index];
|
|
|
|
worker.available = false;
|
|
|
|
worker.assignedRequestId = requestId;
|
2023-01-26 10:44:57 -06:00
|
|
|
|
2023-01-02 13:14:32 -06:00
|
|
|
// TODO: Notify assignee
|
2023-01-05 01:19:14 -06:00
|
|
|
return worker;
|
2023-01-02 13:14:32 -06:00
|
|
|
}
|
|
|
|
|
2023-01-26 10:44:57 -06:00
|
|
|
async getAssignedWork(workerId) {
|
|
|
|
const worker = this.workers.get(workerId);
|
2023-01-02 13:14:32 -06:00
|
|
|
return worker.assignedRequestId;
|
2023-01-01 21:09:02 -06:00
|
|
|
}
|
|
|
|
}
|