-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat, wip: start to work on message validation for server
- Loading branch information
1 parent
0febf84
commit 33aee12
Showing
13 changed files
with
345 additions
and
196 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
export * from './server/messages' | ||
export * from './server/messages/messages' | ||
export * from './core' | ||
export * from './prompt' | ||
export * from './server/messages' | ||
export * from './server/messages/messages' | ||
export * from './execute' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { LAST_STEP, SteppingSlicer, STEPS_PER_SLICE } from '../../../core' | ||
import net from 'node:net' | ||
import { RShell, TokenMap } from '../../../r-bridge' | ||
import { | ||
answerForValidationError, FileAnalysisRequestMessage, FileAnalysisResponseMessage, | ||
FlowrErrorMessage, FlowrHelloResponseMessage, requestAnalysisMessage, | ||
sendMessage, | ||
SliceRequestMessage, validateBaseMessageFormat, validateMessage | ||
} from './messages' | ||
|
||
export interface FlowRFileInformation { | ||
filename: string, | ||
slicer: SteppingSlicer | ||
} | ||
|
||
export class FlowRServerConnection { | ||
private readonly socket: net.Socket | ||
private readonly shell: RShell | ||
private readonly tokenMap: TokenMap | ||
private readonly name: string | ||
|
||
// maps token to information | ||
private readonly fileMap = new Map<string, FlowRFileInformation>() | ||
|
||
|
||
// we do not have to ensure synchronized shell-access as we are always running synchronized | ||
constructor(socket: net.Socket, name: string, shell: RShell, tokenMap: TokenMap) { | ||
this.socket = socket | ||
this.tokenMap = tokenMap | ||
this.shell = shell | ||
this.name = name | ||
this.socket.on('data', data => this.handleData(String(data))) | ||
} | ||
|
||
// TODO: do we have to deal with partial messages? | ||
private handleData(message: string) { | ||
const request = validateBaseMessageFormat(message) | ||
if(request.type === 'error') { | ||
answerForValidationError(this.socket, request) | ||
return | ||
} | ||
switch(request.message.type) { | ||
case 'request-file-analysis': | ||
this.handleFileAnalysisRequest(request.message as FileAnalysisRequestMessage) | ||
break | ||
case 'request-slice': | ||
this.handleSliceRequest(request.message as SliceRequestMessage) | ||
break | ||
default: | ||
sendMessage<FlowrErrorMessage>(this.socket, { | ||
type: 'error', | ||
fatal: true, | ||
reason: `The message type ${JSON.stringify(request.type ?? 'undefined')} is not supported.` | ||
}) | ||
this.socket.end() | ||
} | ||
} | ||
|
||
// TODO: do not crash with errors! | ||
|
||
// TODO: add name to clients? | ||
// TODO: integrate this with lsp? | ||
private handleFileAnalysisRequest(base: FileAnalysisRequestMessage) { | ||
const requestResult = validateMessage(base, requestAnalysisMessage) | ||
if(requestResult.type === 'error') { | ||
answerForValidationError(this.socket, requestResult) | ||
return | ||
} | ||
const message = requestResult.message | ||
console.log(`[${this.name}] Received file analysis request for ${message.filename} (token: ${message.filetoken})`) | ||
|
||
// TODO: guard with json schema so that all are correctly keys given | ||
if(this.fileMap.has(message.filetoken)) { | ||
console.log(`File token ${message.filetoken} already exists. Overwriting.`) | ||
} | ||
const slicer = new SteppingSlicer({ | ||
stepOfInterest: LAST_STEP, | ||
shell: this.shell, | ||
tokenMap: this.tokenMap, | ||
request: { | ||
request: 'text', | ||
content: message.content, | ||
attachSourceInformation: true, | ||
ensurePackageInstalled: true | ||
}, | ||
criterion: [] // currently unknown | ||
// TODO: allow to configure the rest? | ||
}) | ||
this.fileMap.set(message.filetoken, { | ||
filename: message.filename, | ||
slicer | ||
}) | ||
|
||
void slicer.allRemainingSteps(false).then(results => { | ||
sendMessage(this.socket, { | ||
type: 'response-file-analysis', | ||
success: true, | ||
results | ||
}) | ||
}) | ||
} | ||
|
||
private handleSliceRequest(request: SliceRequestMessage) { | ||
console.log(`[${request.filetoken}] Received slice request with criteria ${JSON.stringify(request.criterion)}`) | ||
|
||
const fileInformation = this.fileMap.get(request.filetoken) | ||
if(!fileInformation) { | ||
sendMessage<FlowrErrorMessage>(this.socket, { | ||
type: 'error', | ||
fatal: false, | ||
reason: `The file token ${request.filetoken} has never been analyzed.` | ||
}) | ||
return | ||
} | ||
// TODO: remove failed messages as they are part of error? | ||
// TODO: ensure correct criteria | ||
// TODO: cache slices? | ||
// TODO: unique message ids in requests and answsers to link them? | ||
fileInformation.slicer.updateCriterion(request.criterion) | ||
void fileInformation.slicer.allRemainingSteps(true).then(results => { | ||
sendMessage(this.socket, { | ||
type: 'response-slice', | ||
success: true, | ||
// TODO: is there a better way? | ||
results: Object.fromEntries(Object.entries(results).filter(([k,]) => Object.hasOwn(STEPS_PER_SLICE, k))) | ||
}) | ||
}) | ||
} | ||
|
||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { FlowrBaseMessage, RequestMessageDefinition } from './messages' | ||
import { LAST_PER_FILE_STEP, StepResults } from '../../../../core' | ||
import Joi from 'joi' | ||
import { FlowRServerConnection } from '../connection' | ||
|
||
export interface FileAnalysisRequestMessage extends FlowrBaseMessage { | ||
type: 'request-file-analysis', | ||
filetoken: string, | ||
filename: string, | ||
content: string | ||
} | ||
|
||
|
||
export const requestAnalysisMessage: RequestMessageDefinition<FileAnalysisRequestMessage, [FlowRServerConnection]> = { | ||
type: 'request-file-analysis', | ||
schema: Joi.object({ | ||
type: Joi.string().valid('request-file-analysis').required(), | ||
filetoken: Joi.string().required(), | ||
filename: Joi.string().required(), | ||
content: Joi.string().required() | ||
}), | ||
|
||
handle(message: FileAnalysisRequestMessage, information: [FlowRServerConnection]) { | ||
console.log('received file analysis request') | ||
} | ||
} | ||
|
||
|
||
export interface FileAnalysisResponseMessage extends FlowrBaseMessage { | ||
type: 'response-file-analysis', | ||
results: StepResults<typeof LAST_PER_FILE_STEP> | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { FlowrBaseMessage } from './messages' | ||
|
||
export interface FlowrErrorMessage extends FlowrBaseMessage { | ||
type: 'error', | ||
/** if fatal, the connection will be partially closed afterward */ | ||
fatal: boolean, | ||
reason: string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { VersionInformation } from '../../commands/version' | ||
import { FlowrBaseMessage } from './messages' | ||
|
||
export interface FlowrHelloResponseMessage extends FlowrBaseMessage{ | ||
type: 'hello', | ||
/** a unique name assigned to each client it has no semantic meaning and is only used for debugging */ | ||
clientName: string, | ||
versions: VersionInformation | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './error' | ||
export * from './hello' | ||
export * from './slice' | ||
export * from './analysis' | ||
export * from './messages' |
Oops, something went wrong.