Skip to content

Commit

Permalink
Serverheartbeat now sent through session to UI
Browse files Browse the repository at this point in the history
  • Loading branch information
stricklandrbls committed Jul 25, 2024
1 parent 621c3dd commit 89f7ba5
Show file tree
Hide file tree
Showing 14 changed files with 247 additions and 215 deletions.
2 changes: 1 addition & 1 deletion src/dataEditor/core/editor/dataEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export abstract class DataEditor implements ServiceUser<DataSource> {
protected serviceClient: EditServiceClient,
protected ui: DataEditorUI
) {
serviceClient.onDidProcessRequest = (response) => {
serviceClient.onDidProcess = (response) => {
this.ui.updateUI(response)
}
ui.onInputEvent = (input) => {
Expand Down
3 changes: 1 addition & 2 deletions src/dataEditor/core/service/editService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ export interface EditHandler {
}
export interface EditService {
register(source: DataSource): Promise<EditServiceClient>
activeUsers(): number
}
export interface EditServiceClient {
close(): void
id(): string
request: (request: any) => any
onDidProcessRequest: (response: any) => any
onDidProcess: (response: any) => any
}

export interface DataSource {}
Expand Down
34 changes: 17 additions & 17 deletions src/dataEditor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@ import {
StandaloneEditor,
StandaloneInitializer,
} from './standalone/standaloneEditor'
import { OmegaEditServer } from './omegaEdit/tests/utils/fixtures'
import { OmegaEditServerManager } from './omegaEdit/server'
import { OmegaEditServerManager } from './omegaEdit/server/server'

const editorCommands: Map<
EditorCommand['command'],
EditorCommand['initializer']
> = new Map()

export function RegisterEditor(command: EditorCommand): void {
editorCommands.set(command.command, command.initializer)
}
class DataEditorManager implements vscode.Disposable {
private editors: DataEditor[] = []
private disposables: vscode.Disposable[] = []
Expand All @@ -45,6 +41,22 @@ class DataEditorManager implements vscode.Disposable {
})
}
}

let Manager: DataEditorManager

function registerAllEditorCommands(ctx: vscode.ExtensionContext) {
editorCommands.forEach((initer, command) => {
ctx.subscriptions.push(
vscode.commands.registerCommand(command, async () => {
await Manager.Run(initer)
})
)
})
}

export function RegisterEditor(command: EditorCommand): void {
editorCommands.set(command.command, command.initializer)
}
export const VSCodeFileSelector: FilePathSourceStrategy = {
get: () => {
return new Promise(async (resolve, reject) => {
Expand All @@ -66,19 +78,7 @@ const DefaultEditorCommand: EditorCommand = {
initializer: new StandaloneInitializer(VSCodeFileSelector),
}

let Manager: DataEditorManager

function registerAllEditorCommands(ctx: vscode.ExtensionContext) {
editorCommands.forEach((initer, command) => {
ctx.subscriptions.push(
vscode.commands.registerCommand(command, async () => {
await Manager.Run(initer)
})
)
})
}
export function activate(ctx: vscode.ExtensionContext) {
const config = editor_config.extractConfigurationVariables() // Omega Edit Server specific configurations
Manager = new DataEditorManager(ctx)

registerAllEditorCommands(ctx)
Expand Down
9 changes: 6 additions & 3 deletions src/dataEditor/omegaEdit/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path'
import * as os from 'os'
import { DataSource, GetDataSourceStrategy } from '../core/service/editService'

export class FilePath implements DataSource {
private baseName: string
constructor(private filepath: string) {
Expand All @@ -13,9 +14,7 @@ export class FilePath implements DataSource {
return this.baseName
}
}
export interface FilePathSourceStrategy extends GetDataSourceStrategy {
get(): Promise<FilePath>
}

export namespace FilePath {
export const SystemTmpDirectory = (): FilePath => {
return new FilePath(os.tmpdir())
Expand All @@ -24,3 +23,7 @@ export namespace FilePath {
return new FilePath('.')
}
}

export interface FilePathSourceStrategy extends GetDataSourceStrategy {
get(): Promise<FilePath>
}
25 changes: 25 additions & 0 deletions src/dataEditor/omegaEdit/server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FilePath } from '..'
import { IConfig } from '../../config'

export class Connection {
constructor(
readonly host: string,
readonly port: number
) {}
}

export type GetServerConfigStrategy = () => Promise<ServerConfig>
export class ServerConfig {
readonly conn: Connection
readonly logFile: FilePath
readonly logLevel: string
readonly checkpointPath: string

constructor(config: () => IConfig) {
const { checkpointPath, logFile, logLevel, port } = config()
this.conn = new Connection('127.0.0.1', port)
this.logFile = new FilePath(logFile)
this.logLevel = logLevel
this.checkpointPath = checkpointPath
}
}
File renamed without changes.
Empty file.
83 changes: 83 additions & 0 deletions src/dataEditor/omegaEdit/server/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { createSimpleFileLogger, setLogger } from '@omega-edit/client'
import { ServerConfig } from './config'

import * as fs from 'fs'
import path from 'path'
import XDGAppPaths from 'xdg-app-paths'
export const APP_DATA_PATH: string = XDGAppPaths({ name: 'omega_edit' }).data()

const MAX_LOG_FILES = 5
function rotateLogFiles(logFile: string): void {
interface LogFile {
path: string
ctime: Date
}

// assert(
// MAX_LOG_FILES > 0,
// 'Maximum number of log files must be greater than 0'
// )

if (fs.existsSync(logFile)) {
const logDir = path.dirname(logFile)
const logFileName = path.basename(logFile)

// Get list of existing log files
const logFiles: LogFile[] = fs
.readdirSync(logDir)
.filter((file) => file.startsWith(logFileName) && file !== logFileName)
.map((file) => ({
path: path.join(logDir, file),
ctime: fs.statSync(path.join(logDir, file)).ctime,
}))
.sort((a, b) => b.ctime.getTime() - a.ctime.getTime())

// Delete oldest log files if maximum number of log files is exceeded
while (logFiles.length >= MAX_LOG_FILES) {
const fileToDelete = logFiles.pop() as LogFile
fs.unlinkSync(fileToDelete.path)
}

// Rename current log file with timestamp and create a new empty file
const timestamp = new Date().toISOString().replace(/:/g, '-')
fs.renameSync(logFile, path.join(logDir, `${logFileName}.${timestamp}`))
}
}

export function setupLogging(config: ServerConfig): Promise<void> {
return new Promise((res, rej) => {
const filePath = config.logFile.fullPath()
const level = config.logLevel
rotateLogFiles(filePath)
setLogger(createSimpleFileLogger(filePath, level))
res()
})
}

export function generateLogbackConfigFile(server: ServerConfig): string {
const serverLogFile = path.join(APP_DATA_PATH, `serv-${server.conn.port}.log`)
const dirname = path.dirname(server.logFile.fullPath())
if (!fs.existsSync(dirname)) {
fs.mkdirSync(dirname, { recursive: true })
}
const logbackConfig = `<?xml version="1.0" encoding="UTF-8"?>\n
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${serverLogFile}</file>
<encoder>
<pattern>[%date{ISO8601}] [%level] [%logger] [%marker] [%thread] - %msg MDC: {%mdc}%n</pattern>
</encoder>
</appender>
<root level="${server.logLevel.toUpperCase()}">
<appender-ref ref="FILE" />
</root>
</configuration>
`
const logbackConfigFile = path.join(
APP_DATA_PATH,
`serv-${server.conn.port}.logconf.xml`
)
rotateLogFiles(server.logFile.fullPath())
fs.writeFileSync(logbackConfigFile, logbackConfig)
return logbackConfigFile // Return the path to the logback config file
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
import { FilePath } from '.'
import { OmegaEditService } from './editService'
import { FilePath } from '..'
import { OmegaEditService } from '../service/editService'
import path from 'path'
import * as fs from 'fs'
import * as os from 'os'
import XDGAppPaths from 'xdg-app-paths'
import {
createSimpleFileLogger,
getClientVersion,
getServerHeartbeat,
getServerInfo,
IServerHeartbeat,
IServerInfo,
setLogger,
startServer,
stopProcessUsingPID,
stopServerGraceful,
} from '@omega-edit/client'
import { IConfig } from '../config'
import { IHeartbeatInfo } from '../include/server/heartbeat/HeartBeatInfo'
export const APP_DATA_PATH: string = XDGAppPaths({ name: 'omega_edit' }).data()
import { IConfig } from '../../config'
import { IHeartbeatInfo } from '../../include/server/heartbeat/HeartBeatInfo'

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 18.20.1, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 16, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 18.20.1, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 16, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 18.20.1, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: ubuntu-20.04, Node: 16, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 16, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 16, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 16, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 18.20.1, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 18.20.1, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 18.20.1, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 18.20.1, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: macos-12, Node: 18.20.1, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 18.20.1, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 16, Java: 11)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 16, Java: 17)

'IHeartbeatInfo' is declared but its value is never read.

Check failure on line 16 in src/dataEditor/omegaEdit/server/server.ts

View workflow job for this annotation

GitHub Actions / Build, Test, and Package (OS: windows-2019, Node: 16, Java: 8)

'IHeartbeatInfo' is declared but its value is never read.
import { ServerConfig } from './config'
import {
APP_DATA_PATH,
generateLogbackConfigFile,
setupLogging,
} from './logging'

export class Connection {
constructor(
readonly host: string,
readonly port: number
) {}
const activeServers: Map<ServerConfig, OmegaEditServer> = new Map()
const ServerDisposeAll = {
dispose: () => {
activeServers.forEach((server) => {
server.dispose()
})
},
}

export class OmegaEditServer {
private service: OmegaEditService
private heartbeatIntervalId: NodeJS.Timeout | undefined = undefined
constructor(readonly config: ServerConfig) {
this.service = new OmegaEditService(new FilePath(config.checkpointPath))

this.service.onAllSessionsClosed(() => {
clearInterval(this.heartbeatIntervalId)
serverStop(this.config)
})
}
Expand All @@ -45,40 +51,6 @@ export class OmegaEditServer {
}
}

function setupLogging(config: ServerConfig): Promise<void> {
return new Promise((res, rej) => {
const filePath = config.logFile.fullPath()
const level = config.logLevel
rotateLogFiles(filePath)
setLogger(createSimpleFileLogger(filePath, level))
res()
})
}
export class ServerConfig {
readonly conn: Connection
readonly logFile: FilePath
readonly logLevel: string
readonly checkpointPath: string

constructor(config: () => IConfig) {
const { checkpointPath, logFile, logLevel, port } = config()
this.conn = new Connection('127.0.0.1', port)
this.logFile = new FilePath(logFile)
this.logLevel = logLevel
this.checkpointPath = checkpointPath
}
}

export type GetServerConfigStrategy = () => Promise<ServerConfig>

const activeServers: Map<ServerConfig, OmegaEditServer> = new Map()
const ServerDisposeAll = {
dispose: () => {
activeServers.forEach((server) => {
server.dispose()
})
},
}
export class OmegaEditServerManager {
static Connect(config: () => IConfig): Promise<OmegaEditServer> {
return new Promise(async (res, rej) => {
Expand Down Expand Up @@ -119,71 +91,6 @@ function removeDirectory(dirPath: string): void {
fs.rmdirSync(dirPath)
}
}
const MAX_LOG_FILES = 5
function rotateLogFiles(logFile: string): void {
interface LogFile {
path: string
ctime: Date
}

// assert(
// MAX_LOG_FILES > 0,
// 'Maximum number of log files must be greater than 0'
// )

if (fs.existsSync(logFile)) {
const logDir = path.dirname(logFile)
const logFileName = path.basename(logFile)

// Get list of existing log files
const logFiles: LogFile[] = fs
.readdirSync(logDir)
.filter((file) => file.startsWith(logFileName) && file !== logFileName)
.map((file) => ({
path: path.join(logDir, file),
ctime: fs.statSync(path.join(logDir, file)).ctime,
}))
.sort((a, b) => b.ctime.getTime() - a.ctime.getTime())

// Delete oldest log files if maximum number of log files is exceeded
while (logFiles.length >= MAX_LOG_FILES) {
const fileToDelete = logFiles.pop() as LogFile
fs.unlinkSync(fileToDelete.path)
}

// Rename current log file with timestamp and create a new empty file
const timestamp = new Date().toISOString().replace(/:/g, '-')
fs.renameSync(logFile, path.join(logDir, `${logFileName}.${timestamp}`))
}
}

function generateLogbackConfigFile(server: ServerConfig): string {
const serverLogFile = path.join(APP_DATA_PATH, `serv-${server.conn.port}.log`)
const dirname = path.dirname(server.logFile.fullPath())
if (!fs.existsSync(dirname)) {
fs.mkdirSync(dirname, { recursive: true })
}
const logbackConfig = `<?xml version="1.0" encoding="UTF-8"?>\n
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${serverLogFile}</file>
<encoder>
<pattern>[%date{ISO8601}] [%level] [%logger] [%marker] [%thread] - %msg MDC: {%mdc}%n</pattern>
</encoder>
</appender>
<root level="${server.logLevel.toUpperCase()}">
<appender-ref ref="FILE" />
</root>
</configuration>
`
const logbackConfigFile = path.join(
APP_DATA_PATH,
`serv-${server.conn.port}.logconf.xml`
)
rotateLogFiles(server.logFile.fullPath())
fs.writeFileSync(logbackConfigFile, logbackConfig)
return logbackConfigFile // Return the path to the logback config file
}

async function serverStop(server: ServerConfig) {
const serverPidFile = getPidFile(server.conn.port)
Expand Down
Loading

0 comments on commit 89f7ba5

Please sign in to comment.