-
Notifications
You must be signed in to change notification settings - Fork 1
Integrate Conductor into java-slang #95
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
18d8da4
d637754
6d73dab
ef3a3f2
ed2b8f6
08b9345
1b1ec53
1ddea74
ffedd16
e1f8876
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| name: Build and deploy runner | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build runner | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Enable corepack | ||
| run: corepack enable | ||
|
|
||
| - name: Setup node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: yarn | ||
|
|
||
| - name: Install dependencies | ||
| run: yarn install --frozen-lockfile | ||
|
|
||
| - name: Build | ||
| run: yarn run build --all || yarn build | ||
|
|
||
| - name: Upload artifacts | ||
| id: deployment | ||
| uses: actions/upload-pages-artifact@v3 | ||
| with: | ||
| path: dist/ | ||
|
|
||
| deploy: | ||
| needs: build | ||
| name: Deploy runner | ||
| permissions: | ||
| pages: write | ||
| id-token: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Deploy to GitHub Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@v4 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import setupJVM from '../jvm/index' | ||
| import BasicEvaluator, { IRunnerPlugin } from './runner' | ||
|
|
||
| /** | ||
| * Minimal Java conductor evaluator stub. | ||
| * Currently this evaluator is a placeholder that demonstrates how to | ||
| * integrate with the local JVM runner. It expects class file bytes | ||
| * encoded as a base64 string when used via conductor channels. | ||
| */ | ||
| export class JavaEvaluator extends BasicEvaluator { | ||
| constructor(conductor: IRunnerPlugin) { | ||
| super(conductor) | ||
| } | ||
|
|
||
| async evaluateChunk(_chunk: string): Promise<void> { | ||
| this.conductor.sendOutput('JavaEvaluator: evaluateChunk not supported; use evaluateFile with a .class file encoded as base64') | ||
| } | ||
|
|
||
| async evaluateFile(fileName: string, fileContent: string): Promise<void> { | ||
| try { | ||
| if (fileName.endsWith('.class')) { | ||
| // Expect class file content as base64 to allow conductor transport via JSON | ||
| Buffer.from(fileContent, 'base64') | ||
| // NOTE: we intentionally do not parse the class bytes here in the stub | ||
| // to avoid coupling the evaluator to the full classfile parser. A future | ||
| // implementation may call `parseBin` and then load into the JVM. | ||
| // create a JVM and run the Main class if present (not implemented in this stub) | ||
| setupJVM({ | ||
| callbacks: { | ||
| readFileSync: (path: string) => { | ||
| throw new Error('readFileSync not available in conductor JavaEvaluator') | ||
| }, | ||
| stdout: (m: string) => this.conductor.sendOutput(m), | ||
| stderr: (m: string) => this.conductor.sendOutput(`ERR: ${m}`) | ||
| } | ||
| }) | ||
|
kjw142857 marked this conversation as resolved.
Outdated
|
||
| // Register a readFileSync that returns our in-memory class when requested | ||
| // The JVM runner currently expects classes on disk; for now we run using a minimal approach | ||
| this.conductor.sendOutput('JavaEvaluator: running class via in-memory runner is not yet implemented') | ||
| this.conductor.sendResult('') | ||
| return | ||
| } | ||
|
|
||
| this.conductor.sendOutput('JavaEvaluator: unsupported file type') | ||
| } catch (err) { | ||
| this.conductor.sendError(`${err instanceof Error ? err.message : String(err)}`) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export default JavaEvaluator | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { JavaEvaluator } from '../JavaEvaluator' | ||
| import { IRunnerPlugin } from '../runner' | ||
|
|
||
| class MockConductor implements IRunnerPlugin { | ||
| outputs: string[] = [] | ||
| results: string[] = [] | ||
| errors: string[] = [] | ||
| statuses: Array<{ s: string; a: boolean }> = [] | ||
| sendOutput(message: string): void { | ||
| this.outputs.push(message) | ||
| } | ||
| sendResult(result: string): void { | ||
| this.results.push(result) | ||
| } | ||
| sendError(error: string): void { | ||
| this.errors.push(error) | ||
| } | ||
| updateStatus(status: any, isActive: boolean): void { | ||
| this.statuses.push({ s: String(status), a: isActive }) | ||
| } | ||
| } | ||
|
|
||
| test('evaluateFile with unsupported file emits message', async () => { | ||
| const mock = new MockConductor() | ||
| const ev = new JavaEvaluator(mock) | ||
| await ev.evaluateFile('hello.txt', 'console') | ||
| expect(mock.outputs.length).toBeGreaterThan(0) | ||
| expect(mock.outputs[0]).toMatch(/unsupported file type/) | ||
| expect(mock.errors.length).toBe(0) | ||
| }) | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a test-case where the |
||
| test('evaluateFile with .class base64 emits placeholder run message and result', async () => { | ||
| const mock = new MockConductor() | ||
| const ev = new JavaEvaluator(mock) | ||
| // Use a minimal dummy classfile header (CAFEBABE) as base64; the evaluator | ||
| // stub only inspects bytes and currently does not run them. | ||
| const buf = Buffer.from([0xca, 0xfe, 0xba, 0xbe]) | ||
| const b64 = buf.toString('base64') | ||
| await ev.evaluateFile('Main.class', b64) | ||
| // JavaEvaluator currently emits a placeholder message then a result string | ||
| expect(mock.outputs.some(o => /running class via in-memory runner is not yet implemented/.test(o))).toBe(true) | ||
| // sendResult is called with an empty string in the stub | ||
| expect(mock.results.length).toBeGreaterThanOrEqual(1) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // `__EVALUATOR__` is replaced at build time by bundlers in other projects. | ||
| // We declare it here for type compatibility when bundle replacement is used. | ||
| declare const __EVALUATOR__: any | ||
|
|
||
| export default __EVALUATOR__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { JavaEvaluator } from './JavaEvaluator' | ||
| export { default as BasicEvaluator } from './runner' |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||||
| import { initialise } from './runner' | ||||||||
| // @ts-expect-error — __EVALUATOR__ is replaced at build time by bundlers | ||||||||
| import { __EVALUATOR__ } from './index' | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of importing
Suggested change
|
||||||||
|
|
||||||||
| initialise(__EVALUATOR__) | ||||||||
|
kjw142857 marked this conversation as resolved.
Outdated
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| export type RunnerStatus = 'IDLE' | 'RUNNING' | 'ERROR' | 'FINISHED' | ||
|
|
||
| export interface IRunnerPlugin { | ||
| sendOutput(message: string): void | ||
| sendResult(result: string): void | ||
| sendError(error: string): void | ||
| updateStatus(status: RunnerStatus, isActive: boolean): void | ||
| } | ||
|
|
||
| export abstract class BasicEvaluator { | ||
| protected conductor: IRunnerPlugin | ||
| constructor(conductor: IRunnerPlugin) { | ||
| this.conductor = conductor | ||
| } | ||
|
|
||
| abstract evaluateChunk(chunk: string): Promise<void> | ||
|
|
||
| async evaluateFile(fileName: string, fileContent: string): Promise<void> { | ||
| // default: treat file content as a single chunk | ||
| await this.evaluateChunk(fileContent) | ||
| } | ||
| } | ||
|
|
||
| export function initialise(_evaluator: any) { | ||
| // This is a minimal shim for initialise used in bundling entrypoints. | ||
| // Real conductor runner initialisation is out of scope for this repo. | ||
|
kjw142857 marked this conversation as resolved.
Outdated
|
||
| return | ||
| } | ||
|
|
||
| export default BasicEvaluator | ||
Uh oh!
There was an error while loading. Please reload this page.