Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | 28x 28x 28x 28x 28x 28x 28x | /**
* StorageServer.ts
*
* A server-side class that "has a" local WalletStorage (like a StorageKnex instance),
* and exposes it via a JSON-RPC POST endpoint using Express.
*/
import express, { Request, Response } from "express"
import { AuthMiddlewareOptions, createAuthMiddleware } from "@bsv/auth-express-middleware"
import { createPaymentMiddleware } from "@bsv/payment-express-middleware"
import { ProtoWallet, Wallet } from '@bsv/sdk'
import { sdk } from '..'
// You have your local or imported `WalletStorage` interface:
import { WalletStorage } from "./WalletStorage" // adjust import path
// Or your known local implementation:
import { StorageKnex } from "./StorageKnex" // adjust path as needed
export interface WalletStorageServerOptions {
port: number
wallet: Wallet
monetize: boolean
}
export class StorageServer {
private app = express()
private port: number
private walletStorage: sdk.WalletStorage
private wallet: Wallet
private monetize: boolean
constructor(walletStorage: sdk.WalletStorage, options: WalletStorageServerOptions) {
this.walletStorage = walletStorage
this.port = options.port
this.wallet = options.wallet
this.monetize = options.monetize
this.setupRoutes()
}
private setupRoutes(): void {
this.app.use(express.json())
const options: AuthMiddlewareOptions = {
wallet: this.wallet
}
this.app.use(createAuthMiddleware(options))
Iif (this.monetize) {
this.app.use(createPaymentMiddleware({
wallet: this.wallet,
calculateRequestPrice: () => 100
}))
}
// A single POST endpoint for JSON-RPC:
this.app.post("/", async (req: Request, res: Response) => {
debugger
let { jsonrpc, method, params, id } = req.body
Iif (method !== 'getSettings') {
Iif (typeof params[0] !== 'object' || !params[0]) {
params = [{}]
}
}
// Basic JSON-RPC protocol checks:
Iif (jsonrpc !== "2.0" || !method || typeof method !== "string") {
return res.status(400).json({ error: { code: -32600, message: "Invalid Request" } })
}
try {
// Dispatch the method call:
if (typeof (this as any)[method] === "function") {
// if you wanted to handle certain methods on the server class itself
// e.g. this['someServerMethod'](params)
throw new Error("Server method dispatch not used in this approach.")
} else if (typeof (this.walletStorage as any)[method] === "function") {
// method is on the walletStorage:
// Find user
Iif (method !== 'getSettings') {
const user = await this.walletStorage.findUserByIdentityKey(req.auth.identityKey)
if (!user) {
const userId = await this.walletStorage.insertUser({
identityKey: req.auth.identityKey as string,
userId: 0,
created_at: new Date(),
updated_at: new Date()
})
params[0].userId = userId
} else {
params[0].userId = user.userId
}
}
const result = await (this.walletStorage as any)[method](...(params || []))
return res.json({ jsonrpc: "2.0", result, id })
} else {
// Unknown method
return res.status(400).json({
jsonrpc: "2.0",
error: { code: -32601, message: `Method not found: ${method}` },
id
})
}
} catch (error) {
// Catch any thrown errors from the local walletStorage method
const err = error as Error
return res.status(200).json({
jsonrpc: "2.0",
error: {
code: -32000,
message: err.message,
data: {
name: err.name,
stack: err.stack
}
},
id
})
}
})
}
public start(): void {
this.app.listen(this.port, () => {
console.log(`WalletStorageServer listening at http://localhost:${this.port}`)
})
}
}
import Knex from 'knex'
async function main() {
const knexInstance = Knex({
client: 'sqlite3', // or 'mysql', etc.
connection: { filename: './test.db' },
useNullAsDefault: true
})
const storage = new StorageKnex({
knex: knexInstance,
chain: 'main',
feeModel: { model: 'sat/kb', value: 1 },
commissionSatoshis: 0
})
// Must init storage (migrate, or otherwise):
await storage.migrate("MyRemoteStorage")
await storage.makeAvailable()
const serverOptions: WalletStorageServerOptions = { port: 3000, wallet: new ProtoWallet('anyone'), monetize: false }
const server = new StorageServer(storage, serverOptions)
server.start()
}
//main().catch(console.error)
|