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

Restructure the project to meet the template #6

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions logic/leaderboard/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "leaderboard"
description = "leaderboard"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
near-sdk.workspace = true

[dev-dependencies]
near-sdk = { workspace = true, features = ["unit-testing"] }
tokio.workspace = true
near-workspaces.workspace = true
serde_json.workspace = true
17 changes: 17 additions & 0 deletions logic/leaderboard/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
rustup target add wasm32-unknown-unknown
set -e

cd "$(dirname $0)"

TARGET="${CARGO_TARGET_DIR:-../../target}"

cargo build --target wasm32-unknown-unknown --profile app-release

mkdir -p res

cp $TARGET/wasm32-unknown-unknown/app-release/leaderboard.wasm ./res/

if command -v wasm-opt > /dev/null; then
wasm-opt -Oz ./res/leaderboard.wasm -o ./res/leaderboard.wasm
fi
41 changes: 41 additions & 0 deletions logic/leaderboard/relayer/mock-ws-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { WebSocketServer } = require('ws');
const prompt = require('prompt-sync')({ sigint: true });

const wss = new WebSocketServer({ port: 8080 });

console.log('Waiting for a new connection...');

wss.on('connection', function connection(ws) {
let keepAsking = true;
ws.on('error', () => keepAsking = false);

ws.on('message', function message(data) {
console.log('received: %s', data);
});

while (keepAsking) {
console.log('-'.repeat(process.stdout.columns));
const action = prompt('What to do? add-score/get-score: ');
if (action === 'add-score') {
const account = prompt('Account: ');
const app = prompt('Application: ');
const score = parseInt(prompt('score: '));
ws.send(JSON.stringify({
action: 'add-score',
app,
account,
score
}));
} else if (action === 'get-score') {
const account = prompt('Account: ');
const app = prompt('Application: ');
ws.send(JSON.stringify({
action: 'get-score',
app,
account,
}));
} else {
ws.close();
}
}
});
13 changes: 13 additions & 0 deletions logic/leaderboard/relayer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "relayer",
"version": "1.0.0",
"main": "index.js",
"author": "Saeed",
"license": "MIT",
"dependencies": {
"command-line-args": "^5.2.1",
"near-api-js": "^4.0.1",
"prompt-sync": "^4.2.0",
"ws": "^8.17.0"
}
}
149 changes: 149 additions & 0 deletions logic/leaderboard/relayer/relayer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
const nearAPI = require('near-api-js');
const fs = require('fs');
const commandLineArgs = require('command-line-args');
const GameEventListener = require('./ws');

const { Contract } = nearAPI;

const createKeyStore = async () => {
const { KeyPair, keyStores } = nearAPI;

const ACCOUNT_ID = 'highfalutin-act.testnet';
const NETWORK_ID = 'testnet';
const KEY_PATH =
'/home/saeed/.near-credentials/testnet/highfalutin-act.testnet.json';

const credentials = JSON.parse(fs.readFileSync(KEY_PATH));
const myKeyStore = new keyStores.InMemoryKeyStore();
myKeyStore.setKey(
NETWORK_ID,
ACCOUNT_ID,
KeyPair.fromString(credentials.private_key)
);

return myKeyStore;
};

let keyStore;
const connectToNear = async () => {
keyStore = await createKeyStore();
const connectionConfig = {
networkId: 'testnet',
keyStore,
nodeUrl: 'https://rpc.testnet.near.org',
walletUrl: 'https://testnet.mynearwallet.com/',
helperUrl: 'https://helper.testnet.near.org',
explorerUrl: 'https://testnet.nearblocks.io',
};
const { connect } = nearAPI;
const nearConnection = await connect(connectionConfig);
return nearConnection;
};

const addScore = async (account_id, app_name, score) => {
if (contract === null) {
throw new Error('Contract is not initialized');
}

const account = await near.account('highfalutin-act.testnet');
await contract.add_score({
signerAccount: account,
args: {
app_name,
account_id,
score,
},
});
};

const getScore = async (account_id, app_name) => {
if (contract === null) {
throw new Error('Contract is not initialized');
}

return await contract.get_score({
app_name,
account_id,
});
};

const getScores = async (app_name) => {
if (contract === null) {
throw new Error('Contract is not initialized');
}

return await contract.get_scores({
app_name,
});
};

let contract = null;
let near = null;

async function main() {
const optionDefinitions = [
{ name: 'subscribe', type: Boolean },
{ name: 'add-score', type: Boolean },
{ name: 'get-score', type: Boolean },
{ name: 'get-scores', type: Boolean },
{ name: 'account', type: String },
{ name: 'score', type: Number },
{ name: 'app', type: String },
{ name: 'applicationId', type: String },
{ name: 'nodeUrl', type: String },
];

const options = commandLineArgs(optionDefinitions);

const nearConnection = await connectToNear();
near = nearConnection;
contract = new Contract(
nearConnection.connection,
'highfalutin-act.testnet',
{
changeMethods: ['add_score'],
viewMethods: ['get_version', 'get_score', 'get_scores'],
}
);
if (options.subscribe) {
const { applicationId, nodeUrl } = options;
console.log(`Subscribed for the events of ${applicationId}`);
subscribe(applicationId, nodeUrl);
} else if (options['add-score']) {
const { account, app, score } = options;
await addScore(account, app, score);
console.log(
`Score added for account: ${account}, app: ${app}, score: ${score}`
);
} else if (options['get-score']) {
const { account, app } = options;
const score = await getScore(account, app);
console.log(`${account} score is: ${score}`);
} else if (options['get-scores']) {
const { app } = options;
const scores = await getScores(app);
console.log(`Scores for ${app}: ${JSON.stringify(scores)}`);
}
}

let eventListener;
let players = {};
const subscribe = (applicationId, nodeUrl) => {
eventListener = new GameEventListener(nodeUrl, applicationId);
eventListener.on('NewPlayer', (player) => {
players[player.id] = player.name;
});

eventListener.on('GameOver', (winner) => {
addScore(players[winner.winner], 'rsp', 1000).then(() =>
console.log(`Score added for ${players[winner.winner]}`)
).catch(e => {
console.error(`Failed to add the score. ${e}`);
});
});
};

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
50 changes: 50 additions & 0 deletions logic/leaderboard/relayer/ws.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

// Listen for messages
const WebSocket = require('ws');

module.exports = class GameEventListener {
constructor(nodeUrl, applicationId) {
this.ws = new WebSocket(`${nodeUrl}/ws`);
this.ws.on('open', () => {
const request = {
id: this.getRandomRequestId(),
method: 'subscribe',
params: {
applicationIds: [applicationId],
},
};
this.ws.send(JSON.stringify(request));
});

this.events = {};
this.ws.on('message', async (event) => {
const utf8Decoder = new TextDecoder('UTF-8');
const data = utf8Decoder.decode(event);
await this.parseMessage(data);
});
}

on(event, func) {
this.events[event] = func;
}

parseMessage(msg) {
try {
const event = JSON.parse(msg);
for (const e of event.result.data.events) {
if (e.kind in this.events) {
let bytes = new Int8Array(e.data);
let str = new TextDecoder().decode(bytes);
this.events[e.kind](JSON.parse(str));
}
}
} catch (e) {
console.error(`Failed to parse the json: ${e}`);
}
}

getRandomRequestId() {
return Math.floor(Math.random() * Math.pow(2, 32));
}
};

Loading
Loading