TCP 서버 모드 추가

This commit is contained in:
현성필
2025-01-21 13:19:21 +09:00
parent e23684d833
commit cb9201ddd2
106 changed files with 17710 additions and 0 deletions
@@ -0,0 +1,200 @@
class ApiLayoutItemTreeBuilder {
static createTree(layoutItems) {
layoutItems.sort((a, b) => a.loutItemSerno - b.loutItemSerno);
const rootId = layoutItems.length === 0 ? 0 : parseInt(layoutItems[0].parent);
const root = {id: rootId, children: [], loutItemSerno: 0, loutItemName: 'Root', loutItemDesc: 'Root', loutItemType: '', loutItemDepth: 0, parent: null};
const nodeMap = new Map();
nodeMap.set(rootId, root);
for (const item of layoutItems) {
if (['Grid', 'Group'].includes(item.loutItemType)) {
if (item.loutItemOccCnt !== null) {
if (item.loutItemOccCnt === '*') {
let refItem = layoutItems.find(p => p.loutItemName === item.loutItemOccRef);
if (refItem) {
item.childOccCnt = parseInt(refItem.value, 10);
}
} else {
item.childOccCnt = parseInt(item.loutItemOccCnt, 10);
}
}
}
if (nodeMap.has(parseInt(item.parent))) {
nodeMap.get(parseInt(item.parent)).children.push(item);
// console.log(item.id + ' to ' + item.parent);
} else {
console.log('Parent not found: ' + item.parent);
}
nodeMap.set(item.id, item);
}
return root;
}
static moveNode(root, node, moveUp) {
const parent = this.getParentNode(root, node);
if (parent === null) {
// Node is the root node, cannot be moved
return;
}
const siblings = parent.children;
const currentIndex = siblings.indexOf(node);
if (currentIndex === -1) {
// Node not found in parent's children list
return;
}
const newIndex = moveUp ? currentIndex - 1 : currentIndex + 1;
if (newIndex >= 0 && newIndex < siblings.length) {
// Swap the positions of the current node and the node at the new index
[siblings[currentIndex], siblings[newIndex]] = [siblings[newIndex], siblings[currentIndex]];
}
}
static getParentNode(root, node) {
if (node.parent === null) {
return null; // Node is the root node
}
return this.getNodeById(root, node.parent);
}
static getNodeIndex(parent, node) {
return parent.children.indexOf(node);
}
static getNodeById(node, id) {
if (node.id == id) {
return node;
}
for (const child of node.children) {
const found = this.getNodeById(child, id);
if (found !== null) {
return found;
}
}
return null;
}
static findParent(root, node) {
if (root === null || node === null) {
return null; // Invalid input
}
if (root.children.includes(node)) {
return root; // The root is the parent of the node
}
for (const child of root.children) {
const parent = this.findParent(child, node);
if (parent !== null) {
return parent;
}
}
return null; // Node not found in the tree
}
static printTree(root) {
console.log('====================================');
this.printNode(root, 0);
console.log('====================================');
}
static printNode(node, level) {
if (node === null) {
return;
}
// Print indentation based on the level
let indent = '';
for (let i = 0; i < level; i++) {
indent += ' ';
}
// Print the node information
console.log(`${indent}${node.id}: ${node.loutName}[${node.loutItemType}, Level: ${node.loutItemDepth}, Serno: ${node.loutItemSerno}]`);
// Recursively print the children
if (node.children.length > 0) {
for (const child of node.children) {
this.printNode(child, level + 1);
}
}
}
static moveNodeDepth(root, node, newDepth) {
if (node === null || root === null || newDepth < 0) {
// Invalid input
return;
}
const parent = this.getParentNode(root, node);
if (parent === null) {
// Node is the root node, cannot be moved to a different level
return;
}
const currentDepth = node.loutItemDepth;
const nodeIndex = this.getNodeIndex(parent, node);
const nextSibling = this.findClosestSibling(parent.children, nodeIndex);
parent.children.splice(nodeIndex, 1);
if (newDepth > currentDepth) {
// Moving to a higher depth
if (nextSibling !== null) {
nextSibling.children.push(node);
node.parent = nextSibling.id;
node.loutItemDepth = newDepth;
this.adjustChildrenDepth(node, newDepth + 1);
} else {
// No next sibling found, add the node back to the original parent
parent.children.push(node);
}
} else {
// Moving to a lower depth
const newParent = this.findParent(root, parent);
if (newParent !== null) {
newParent.children.push(node);
node.parent = newParent.id;
node.loutItemDepth = newDepth;
this.adjustChildrenDepth(node, newDepth + 1);
} else {
// No parent found at the desired level, add the node back to the original parent
parent.children.push(node);
}
}
}
static adjustChildrenDepth(node, depth) {
for (const child of node.children) {
child.loutItemDepth = depth;
this.adjustChildrenDepth(child, depth + 1);
}
}
static findNextSibling(siblings) {
if (siblings === null || siblings.length === 0) {
return null;
}
return siblings[0];
}
static findClosestSibling(siblings, nodeIndex) {
if (siblings === null || siblings.length === 0) {
return null;
}
if (nodeIndex < 1 || nodeIndex >= siblings.length) {
return this.findNextSibling(siblings);
}
return siblings[nodeIndex - 1];
}
}
export default ApiLayoutItemTreeBuilder;
@@ -0,0 +1,51 @@
class ApiLayoutItemTreeDataBuilder {
constructor(startId = 10000) {
this.idCounter = this.generateId(startId);
this.nodeMap = new Map();
}
* generateId(start) {
let id = start;
while (true) {
yield id++;
}
}
cloneNode(node, parent) {
// Create a shallow copy of the node, except for the children array
let newNode = {
...node,
id: this.idCounter.next().value, // Update with a new unique ID
parent: parent ? parent.id : undefined // Set the new parent's ID if parent exists
};
// Remove children property to handle it separately
delete newNode.children;
this.nodeMap.set(newNode.id, newNode);
return newNode;
}
replicateTree(node, parent = null) {
const newNode = this.cloneNode(node, parent);
newNode.children = []; // Initialize children array
if (node.children && node.children.length > 0) {
node.children.forEach(child => {
const childCount = node.childOccCnt || 1;
for (let i = 0; i < childCount; i++) {
const childReplicas = this.replicateTree(child, newNode);
newNode.children = newNode.children.concat(childReplicas);
}
});
}
return [newNode]; // Return an array containing only the new singular parent node with replicated children
}
createReplicatedTree(originalTree) {
// console.log({originalTree});
return this.replicateTree(originalTree)[0]; // Return the first element to maintain the tree structure
}
}
export default ApiLayoutItemTreeDataBuilder;
+272
View File
@@ -0,0 +1,272 @@
export const fillPadding = async (apiRequest, value, dataLength) => {
let paddedValue = value; // In real app, this would be processed by APIClient
while (paddedValue.length < dataLength) {
paddedValue = ' ' + paddedValue;
}
return paddedValue;
};
class APIClient {
constructor() {
// Initialize global variables store
window.globals = window.globals || {};
this.abortController = null;
this.contextPath = document.querySelector('meta[name="context-path"]')?.getAttribute('content') || '/';
if (!this.contextPath.endsWith('/')) {
this.contextPath += '/';
}
}
getClientUrl() {
return `${this.contextPath}mgmt/api/test.do`;
}
// Format response for consistency
formatResponse(data) {
return {
body: data.body,
status: data.status,
headers: data.headers.reduce((acc, header) => {
acc[header.key] = header.value;
return acc;
}, {}),
size: data.size
};
}
// Abort ongoing requests
abort() {
if (this.abortController) {
this.abortController.abort();
this.abortController = null;
}
}
// Make the actual API request
async makeAjaxRequest(processedRequest) {
this.abortController = new AbortController();
try {
const response = await fetch(this.getClientUrl(), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': document.querySelector('meta[name="_csrf"]')?.getAttribute('content')
},
body: JSON.stringify(processedRequest),
signal: this.abortController.signal
});
if (!response.ok) {
throw new Error('Network request failed');
}
return response;
} catch (error) {
if (error.name === 'AbortError') {
// Handle abort silently
return null;
}
throw error;
}
}
// Process pre-script and variables
async processPreScriptAndVariables(model, value, consoleOutput) {
const variables = {};
const updatedModel = await this.executePreRequestScript(model, variables, consoleOutput);
return this.replacePlaceholderValueWithVariables(updatedModel, value, variables);
}
// Replace placeholder values with actual variables
replacePlaceholderValueWithVariables(model, originalValue, variables = {}) {
const mergedVariables = {
...window.globals,
...variables
};
return Object.entries(mergedVariables).reduce((value, [key, replacement]) => {
const placeholder = `{{${key}}}`;
return value.replace(new RegExp(placeholder, 'g'), replacement);
}, originalValue);
}
// Main method to send API requests
async sendAPIRequest(model, preProcessCallback, consoleOutput) {
try {
// Execute pre-request script and get variables
const variables = {};
const updatedModel = await this.executePreRequestScript(model, variables, consoleOutput);
// Process request with variables
const processedRequest = this.replacePlaceholdersWithVariables(updatedModel, variables);
// Allow pre-processing if callback provided
if (preProcessCallback) {
preProcessCallback(processedRequest);
}
// Make the request
const response = await this.makeAjaxRequest(processedRequest, consoleOutput);
if (!response) return null;
const responseData = await response.json();
if (!response.ok) {
throw new Error(responseData.error || 'Unknown error');
}
// Format response
const finalResponse = this.formatResponse(responseData);
// Execute post-request script
return this.executePostRequestScript(
model.postRequestScript,
variables,
processedRequest,
finalResponse,
consoleOutput
).catch(error => {
console.error('Post-request script error:', error);
return finalResponse;
});
} catch (error) {
throw new Error(`API 호출 중 오류가 발생했습니다. 사유[${error.message}]`);
}
}
// Replace placeholders in request with variables
replacePlaceholdersWithVariables(original, variables = {}) {
const request = JSON.parse(JSON.stringify(original));
const mergedVariables = {
...window.globals,
...variables
};
Object.entries(mergedVariables).forEach(([key, value]) => {
const placeholder = new RegExp(`{{${key}}}`, 'g');
// Replace in path
request.path = request.path.replace(placeholder, value);
// Replace in request body
if (request.requestBody) {
request.requestBody = request.requestBody.replace(placeholder, value);
}
// Replace in headers
if (request.headers?.length) {
request.headers = JSON.parse(
JSON.stringify(request.headers).replace(placeholder, value)
);
}
// Replace in query params
if (request.queryParams?.length) {
request.queryParams = JSON.parse(
JSON.stringify(request.queryParams).replace(placeholder, value)
);
}
});
return request;
}
// Execute pre-request script in an iframe
executePreRequestScript(model, variables, consoleOutput) {
return new Promise((resolve, reject) => {
const resultFrame = document.getElementById('preRequest');
if (!resultFrame) {
console.warn('preRequest iframe not found');
resolve(model);
return;
}
window.preRequestComplete = (updatedModel, error) => {
if (error) {
reject(error);
} else {
resolve(updatedModel);
}
};
window.temp_variable = variables;
window.currentRequest = model;
window.consoleOutput = consoleOutput;
resultFrame.srcdoc = `
<script>
var oldLog = console.log;
console.log = function(message) {
if(window.parent.consoleOutput)
window.parent.consoleOutput(message);
oldLog.apply(console, arguments);
};
window.globals = window.parent.globals;
window.variables = window.parent.temp_variable;
window.request = window.parent.currentRequest;
try {
${model.preRequestScript || ''}
window.parent.preRequestComplete(window.request, null);
} catch (error) {
window.parent.preRequestComplete(null, error);
}
</script>
`;
});
}
// Execute post-request script in an iframe
executePostRequestScript(script, variables, request, response, consoleOutput) {
return new Promise((resolve, reject) => {
const resultFrame = document.getElementById('postRequest');
if (!resultFrame) {
console.warn('postRequest iframe not found');
resolve(response);
return;
}
window.request = request;
window.response = response;
window.temp_variable = variables;
window.postRequestComplete = (response, error) => {
if (error) {
reject(error);
} else {
resolve(response);
}
};
window.consoleOutput = consoleOutput;
resultFrame.srcdoc = `
<script>
var oldLog = console.log;
console.log = function(message) {
if(window.parent.consoleOutput)
window.parent.consoleOutput(message);
oldLog.apply(console, arguments);
};
window.globals = window.parent.globals;
window.variables = window.parent.temp_variable;
window.request = window.parent.request;
window.response = window.parent.response;
try {
${script || ''}
window.parent.postRequestComplete(window.response, null);
} catch (error) {
window.parent.postRequestComplete(window.response, error.toString());
}
</script>
`;
});
}
}
export default APIClient;
+6
View File
@@ -0,0 +1,6 @@
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge"
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
@@ -0,0 +1,18 @@
export const basePath = (servers, serverId) => {
if (!serverId) return '';
return servers.find(server => server.id == serverId)?.basePath || '';
};
export const getServer = (servers, serverId) => {
return servers.find(server => server.id == serverId);
};
export const getHeader = (headers = [], key) => {
const header = headers.find(header => header.key === key);
if (!header) {
const newHeader = { key, value: '', enabled: true };
headers.push(newHeader);
return newHeader;
}
return header;
};