Skip to main content
Glama
bsim0927
by bsim0927
loader.js5.36 kB
/** * Load and manage poker range files */ import fs from 'fs/promises'; import path from 'path'; import { RangeParser } from './parser.js'; export class RangeLoader { constructor(solverPath) { // Assume ranges/ is a sibling directory to console_solver this.solverDir = path.dirname(solverPath); this.rangesDir = path.join(this.solverDir, 'ranges'); } /** * Load and parse a range file * @param {string} rangePath - Path relative to ranges/ or absolute path * @returns {Promise<Object>} */ async loadRange(rangePath) { if (!rangePath || typeof rangePath !== 'string') { throw new Error('Range path must be a non-empty string'); } const fullPath = path.isAbsolute(rangePath) ? rangePath : path.join(this.rangesDir, rangePath); try { const content = await fs.readFile(fullPath, 'utf8'); const hands = RangeParser.parseRangeFile(content); return { range_string: content.trim(), parsed_hands: hands, hand_count: hands.length, total_combos: RangeParser.calculateCombinations(hands), file_path: fullPath }; } catch (error) { if (error.code === 'ENOENT') { throw new Error(`Range file not found: ${rangePath}`); } throw new Error(`Failed to load range file: ${error.message}`); } } /** * Check if range file exists * @param {string} rangePath * @returns {Promise<boolean>} */ async rangeExists(rangePath) { const fullPath = path.isAbsolute(rangePath) ? rangePath : path.join(this.rangesDir, rangePath); try { await fs.access(fullPath); return true; } catch { return false; } } /** * Get full path for a range file * @param {string} rangePath * @returns {string} */ getFullPath(rangePath) { return path.isAbsolute(rangePath) ? rangePath : path.join(this.rangesDir, rangePath); } /** * List all range files in the ranges directory * @returns {Promise<Array>} */ async listRangeFiles() { try { const ranges = []; // Recursively walk the ranges directory const walk = async (dir, prefix = '') => { const files = await fs.readdir(dir, { withFileTypes: true }); for (const file of files) { const fullPath = path.join(dir, file.name); const relativePath = prefix ? `${prefix}/${file.name}` : file.name; if (file.isDirectory()) { await walk(fullPath, relativePath); } else if (file.isFile() && (file.name.endsWith('.txt') || !file.name.includes('.'))) { // Include .txt files and files without extension ranges.push({ path: relativePath, full_path: fullPath, name: file.name, size: (await fs.stat(fullPath)).size }); } } }; try { await walk(this.rangesDir); } catch (error) { // Ranges directory might not exist if (error.code !== 'ENOENT') { throw error; } } return ranges.sort((a, b) => a.path.localeCompare(b.path)); } catch (error) { throw new Error(`Failed to list range files: ${error.message}`); } } /** * Filter range files by pattern * @param {string} pattern - Search pattern (e.g., "BTN", "6max") * @returns {Promise<Array>} */ async filterRanges(pattern) { const allRanges = await this.listRangeFiles(); const lowerPattern = pattern.toLowerCase(); return allRanges.filter(range => range.path.toLowerCase().includes(lowerPattern) || range.name.toLowerCase().includes(lowerPattern) ); } /** * Get ranges by set (e.g., "6max", "qb") * @param {string} rangeSet * @returns {Promise<Array>} */ async getRangesBySet(rangeSet) { const allRanges = await this.listRangeFiles(); const setName = rangeSet.toLowerCase(); return allRanges.filter(range => range.path.toLowerCase().includes(setName) ); } /** * Get ranges by position * @param {string} position - e.g., "BTN", "SB", "BB" * @returns {Promise<Array>} */ async getRangesByPosition(position) { const allRanges = await this.listRangeFiles(); const posName = position.toUpperCase(); return allRanges.filter(range => range.path.includes(posName) || range.name.includes(posName) ); } /** * Load multiple ranges at once * @param {Array<string>} paths * @returns {Promise<Object>} */ async loadMultipleRanges(paths) { const results = {}; for (const rangePath of paths) { try { results[rangePath] = await this.loadRange(rangePath); } catch (error) { results[rangePath] = { error: error.message }; } } return results; } /** * Get ranges directory info * @returns {Promise<Object>} */ async getRangesInfo() { try { const stat = await fs.stat(this.rangesDir); const ranges = await this.listRangeFiles(); return { path: this.rangesDir, exists: true, total_files: ranges.length, ranges: ranges }; } catch (error) { return { path: this.rangesDir, exists: false, error: error.message }; } } } export default RangeLoader;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bsim0927/texas-solver-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server