finish database, udp pool
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -29,3 +29,6 @@ coverage
 | 
				
			|||||||
*.sw?
 | 
					*.sw?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*.tsbuildinfo
 | 
					*.tsbuildinfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generated Files
 | 
				
			||||||
 | 
					*.sqlite
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								bun.lock
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								bun.lock
									
									
									
									
									
								
							@@ -6,12 +6,14 @@
 | 
				
			|||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@trpc/client": "^10.45.2",
 | 
					        "@trpc/client": "^10.45.2",
 | 
				
			||||||
        "@trpc/server": "^10.45.2",
 | 
					        "@trpc/server": "^10.45.2",
 | 
				
			||||||
 | 
					        "@types/lodash": "^4.17.16",
 | 
				
			||||||
        "log-symbols": "^7.0.0",
 | 
					        "log-symbols": "^7.0.0",
 | 
				
			||||||
        "pinia": "^3.0.1",
 | 
					        "pinia": "^3.0.1",
 | 
				
			||||||
        "trpc-bun-adapter": "^1.2.2",
 | 
					        "trpc-bun-adapter": "^1.2.2",
 | 
				
			||||||
        "ts-log": "^2.2.7",
 | 
					        "ts-log": "^2.2.7",
 | 
				
			||||||
        "vue": "^3.5.13",
 | 
					        "vue": "^3.5.13",
 | 
				
			||||||
        "vue-router": "4",
 | 
					        "vue-router": "4",
 | 
				
			||||||
 | 
					        "zod": "^3.24.2",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "@tailwindcss/postcss": "^4.0.12",
 | 
					        "@tailwindcss/postcss": "^4.0.12",
 | 
				
			||||||
@@ -243,6 +245,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
 | 
					    "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "@types/lodash": ["@types/lodash@4.17.16", "", {}, "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
 | 
					    "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
 | 
					    "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
 | 
				
			||||||
@@ -557,6 +561,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
 | 
					    "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "@vue/devtools-core/nanoid": ["nanoid@5.1.3", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ=="],
 | 
					    "@vue/devtools-core/nanoid": ["nanoid@5.1.3", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-zAbEOEr7u2CbxwoMRlz/pNSpRP0FdAU4pRaYunCdEezWohXFs+a0Xw7RfkKaezMsmSM1vttcLthJtwRnVtOfHQ=="],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
 | 
					    "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,12 @@
 | 
				
			|||||||
        default = pkgs.mkShell {
 | 
					        default = pkgs.mkShell {
 | 
				
			||||||
          packages = with pkgs; [ 
 | 
					          packages = with pkgs; [ 
 | 
				
			||||||
            bun
 | 
					            bun
 | 
				
			||||||
 | 
					            sqlite
 | 
				
			||||||
 | 
					            sqls
 | 
				
			||||||
 | 
					            dbeaver-bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # LSP
 | 
				
			||||||
 | 
					            typescript-language-server
 | 
				
			||||||
          ];
 | 
					          ];
 | 
				
			||||||
          shellHook = ''
 | 
					          shellHook = ''
 | 
				
			||||||
            export PATH=$PATH:$HOME/.bun/bin
 | 
					            export PATH=$PATH:$HOME/.bun/bin
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,12 +15,14 @@
 | 
				
			|||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@trpc/client": "^10.45.2",
 | 
					    "@trpc/client": "^10.45.2",
 | 
				
			||||||
    "@trpc/server": "^10.45.2",
 | 
					    "@trpc/server": "^10.45.2",
 | 
				
			||||||
 | 
					    "@types/lodash": "^4.17.16",
 | 
				
			||||||
    "log-symbols": "^7.0.0",
 | 
					    "log-symbols": "^7.0.0",
 | 
				
			||||||
    "pinia": "^3.0.1",
 | 
					    "pinia": "^3.0.1",
 | 
				
			||||||
    "trpc-bun-adapter": "^1.2.2",
 | 
					    "trpc-bun-adapter": "^1.2.2",
 | 
				
			||||||
    "ts-log": "^2.2.7",
 | 
					    "ts-log": "^2.2.7",
 | 
				
			||||||
    "vue": "^3.5.13",
 | 
					    "vue": "^3.5.13",
 | 
				
			||||||
    "vue-router": "4"
 | 
					    "vue-router": "4",
 | 
				
			||||||
 | 
					    "zod": "^3.24.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@tailwindcss/postcss": "^4.0.12",
 | 
					    "@tailwindcss/postcss": "^4.0.12",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								server/common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								server/common.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					export function numberToBytes(num: number, bytesLength: number): Uint8Array {
 | 
				
			||||||
 | 
					  var array = new Uint8Array(bytesLength)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var i;
 | 
				
			||||||
 | 
					  for (i = 0; i < bytesLength; i++) {
 | 
				
			||||||
 | 
					    array[i] = num & (0xFF << (i << 3))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return array
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,7 +1,131 @@
 | 
				
			|||||||
import { Database } from "bun:sqlite";
 | 
					import { Database } from "bun:sqlite";
 | 
				
			||||||
 | 
					import { isNumber, isString } from "lodash";
 | 
				
			||||||
 | 
					import { z } from "zod";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const db = new Database("lab.sqlite", { strict: true })
 | 
					const db = new Database("lab.sqlite", { strict: true })
 | 
				
			||||||
 | 
					initDB();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function addUser(name: string, password: string) {
 | 
					
 | 
				
			||||||
  const query = db.query()
 | 
					const boardSchema = z.object({
 | 
				
			||||||
 | 
					  id: z.number(),
 | 
				
			||||||
 | 
					  name: z.string(),
 | 
				
			||||||
 | 
					  room: z.string(),
 | 
				
			||||||
 | 
					  ipv4: z.string().ip({ version: "v4" }),
 | 
				
			||||||
 | 
					  ipv6: z.string().ip({ version: "v6" }),
 | 
				
			||||||
 | 
					  port: z.number().nonnegative(),
 | 
				
			||||||
 | 
					  cmdID: z.number().nonnegative()
 | 
				
			||||||
 | 
					}).partial({
 | 
				
			||||||
 | 
					  ipv6: true,
 | 
				
			||||||
 | 
					  cmdID: true
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Board = z.infer<typeof boardSchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function isBoard(obj: any): obj is Board {
 | 
				
			||||||
 | 
					  return boardSchema.safeParse(obj).success
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const userSchema = z.object({
 | 
				
			||||||
 | 
					  id: z.number(),
 | 
				
			||||||
 | 
					  name: z.string(),
 | 
				
			||||||
 | 
					  password: z.string(),
 | 
				
			||||||
 | 
					  boardID: z.number(),
 | 
				
			||||||
 | 
					}).partial({
 | 
				
			||||||
 | 
					  boardID: true,
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type User = z.infer<typeof userSchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function isUser(obj: any): obj is User {
 | 
				
			||||||
 | 
					  return userSchema.safeParse(obj).success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function initDB() {
 | 
				
			||||||
 | 
					  const tables = allTables()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!tables.includes("Users")) {
 | 
				
			||||||
 | 
					    db.query(`
 | 
				
			||||||
 | 
					      CREATE TABLE Users(
 | 
				
			||||||
 | 
					        id         INT PRIMARY KEY   NOT NULL,
 | 
				
			||||||
 | 
					        name       TEXT              NOT NULL,
 | 
				
			||||||
 | 
					        password   TEXT              NOT NULL
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    `).run();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!tables.includes("Boards"))
 | 
				
			||||||
 | 
					    db.query(`
 | 
				
			||||||
 | 
					      CREATE TABLE Boards(
 | 
				
			||||||
 | 
					        id         INT PRIMARY KEY   NOT NULL,
 | 
				
			||||||
 | 
					        name       TEXT              NOT NULL,
 | 
				
			||||||
 | 
					        room       TEXT              NOT NULL,
 | 
				
			||||||
 | 
					        ipv4       CHAR(16)          NOT NULL,
 | 
				
			||||||
 | 
					        ipv6       CHAR(46)                  ,
 | 
				
			||||||
 | 
					        port       INT               NOT NULL
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    `).run();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function allTables(): Array<string> {
 | 
				
			||||||
 | 
					  const query = db.query(`SELECT name FROM sqlite_master WHERE type='table'`)
 | 
				
			||||||
 | 
					  var tables = new Array()
 | 
				
			||||||
 | 
					  // Flaten array
 | 
				
			||||||
 | 
					  for (const item of query.values()) {
 | 
				
			||||||
 | 
					    tables.push(item[0])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  query.finalize()
 | 
				
			||||||
 | 
					  return tables
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function tableColumnName(table: string): Array<string> {
 | 
				
			||||||
 | 
					  const query = db.query(`PRAGMA table_info(${table})`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var columnName = new Array()
 | 
				
			||||||
 | 
					  for (const column of query.values()) {
 | 
				
			||||||
 | 
					    columnName.push(column[1])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return columnName
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function allBoards() {
 | 
				
			||||||
 | 
					  const query = db.query(`SELECT * FROM Boards`)
 | 
				
			||||||
 | 
					  const boards = query.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  query.finalize()
 | 
				
			||||||
 | 
					  return boards
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function findBoard(id?: number | string): Board {
 | 
				
			||||||
 | 
					  let condition: string
 | 
				
			||||||
 | 
					  if (isNumber(id)) {
 | 
				
			||||||
 | 
					    condition = `id=${id}`
 | 
				
			||||||
 | 
					  } else if (isString(id)) {
 | 
				
			||||||
 | 
					    condition = `name='${id}'`
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    throw new Error("Failure: Wrong type when find board")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const query = db.query(`SELECT * FROM Boards WHERE ${condition}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const spRet = boardSchema.safeParse(query.get())
 | 
				
			||||||
 | 
					  if (spRet.success) {
 | 
				
			||||||
 | 
					    return spRet.data
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    throw new Error(`Not Found ${id} FPGA Board`)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function findUser(name: string): User {
 | 
				
			||||||
 | 
					  const query = db.query(`SELECT * FROM Users WHERE name='${name}'`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const spRet = userSchema.safeParse(query.get())
 | 
				
			||||||
 | 
					  if (spRet.success) {
 | 
				
			||||||
 | 
					    return spRet.data
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    throw new Error(`Failure: Not found ${name} User`)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										159
									
								
								server/equipment.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								server/equipment.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
				
			|||||||
 | 
					import type { Board } from "./database";
 | 
				
			||||||
 | 
					import { boardSchema, findBoard } from "./database";
 | 
				
			||||||
 | 
					import { numberToBytes } from "./common";
 | 
				
			||||||
 | 
					import { z } from "zod";
 | 
				
			||||||
 | 
					import _ from "lodash";
 | 
				
			||||||
 | 
					import { udpSocketPool } from "./udp";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export namespace EquipmentPackage {
 | 
				
			||||||
 | 
					  const HEADER_LENGTH = 8
 | 
				
			||||||
 | 
					  const BYTES_RETURN_ACK = 0b0001_0000
 | 
				
			||||||
 | 
					  const BYTES_TRANSFORM_TYPE = 0b0000_1000
 | 
				
			||||||
 | 
					  const BYTES_READ_WRITE_TYPE = 0b0000_0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const HeaderOptionsSchema = z.object({
 | 
				
			||||||
 | 
					    returnAck: z.boolean(),
 | 
				
			||||||
 | 
					    transformType: z.enum(["Fixed", "Extend"]),
 | 
				
			||||||
 | 
					    readWriteType: z.enum(["r", "w"])
 | 
				
			||||||
 | 
					  }).partial()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export type HeaderOptions = z.infer<typeof HeaderOptionsSchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export function isHeaderOptions(obj: any): obj is HeaderOptions {
 | 
				
			||||||
 | 
					    return HeaderOptionsSchema.safeParse(obj).success
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export class Header {
 | 
				
			||||||
 | 
					    private commandType: number = 0
 | 
				
			||||||
 | 
					    private bytesLength: number = 0
 | 
				
			||||||
 | 
					    private commmandID: number = 0
 | 
				
			||||||
 | 
					    private _reserved: number = 0
 | 
				
			||||||
 | 
					    private address: number = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(options: HeaderOptions) {
 | 
				
			||||||
 | 
					      this.setCommandType(options)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setCommandType(options: HeaderOptions) {
 | 
				
			||||||
 | 
					      const validOptions = HeaderOptionsSchema.parse(options)
 | 
				
			||||||
 | 
					      this.commandType =
 | 
				
			||||||
 | 
					        (validOptions.returnAck === true ? BYTES_RETURN_ACK : 0) |
 | 
				
			||||||
 | 
					        (validOptions.transformType === "Extend" ? BYTES_TRANSFORM_TYPE : 0) |
 | 
				
			||||||
 | 
					        (validOptions.readWriteType === "w" ? BYTES_READ_WRITE_TYPE : 0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setBytesLength(length: number) {
 | 
				
			||||||
 | 
					      this.bytesLength = length
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setAddress(address: number) {
 | 
				
			||||||
 | 
					      this.address = address
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getCommandType(): HeaderOptions {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        returnAck: ((this.commandType & BYTES_RETURN_ACK) === BYTES_RETURN_ACK ? true : false),
 | 
				
			||||||
 | 
					        transformType: ((this.commandType & BYTES_TRANSFORM_TYPE) === BYTES_TRANSFORM_TYPE ? "Extend" : "Fixed"),
 | 
				
			||||||
 | 
					        readWriteType: ((this.commandType & BYTES_READ_WRITE_TYPE) === BYTES_READ_WRITE_TYPE ? "w" : "r")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    incCommandID() {
 | 
				
			||||||
 | 
					      this.commmandID++
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clearCommandID() {
 | 
				
			||||||
 | 
					      this.commmandID = 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toUint8Array(): Uint8Array {
 | 
				
			||||||
 | 
					      var array = new Uint8Array(HEADER_LENGTH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      array[0] = this.commandType
 | 
				
			||||||
 | 
					      array[1] = this.bytesLength
 | 
				
			||||||
 | 
					      array[2] = this.commmandID
 | 
				
			||||||
 | 
					      array[3] = this._reserved
 | 
				
			||||||
 | 
					      array[4] = this._reserved
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let addressBytes = numberToBytes(this.address, 3)
 | 
				
			||||||
 | 
					      array[5] = addressBytes[0]
 | 
				
			||||||
 | 
					      array[6] = addressBytes[1]
 | 
				
			||||||
 | 
					      array[7] = addressBytes[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return array
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export class Package {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private header: Header
 | 
				
			||||||
 | 
					    private body: Uint8Array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(header: Header | HeaderOptions, body?: Uint8Array) {
 | 
				
			||||||
 | 
					      if (header instanceof Header) {
 | 
				
			||||||
 | 
					        this.header = header
 | 
				
			||||||
 | 
					      } else if (isHeaderOptions(header)) {
 | 
				
			||||||
 | 
					        this.header = new Header(header)
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw Error("Create EquipmentSocket Failure!")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.body = (body === undefined) ? new Uint8Array(0) : _.cloneDeep(body)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toUint8Array(): Uint8Array {
 | 
				
			||||||
 | 
					      const header = this.header.toUint8Array()
 | 
				
			||||||
 | 
					      const bodyLength = this.body.length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let total = new Uint8Array(header.length + bodyLength)
 | 
				
			||||||
 | 
					      total.set(header)
 | 
				
			||||||
 | 
					      if (bodyLength > 0)
 | 
				
			||||||
 | 
					        total.set(this.body, header.length)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return total
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Equipment {
 | 
				
			||||||
 | 
					  board: Board
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(name?: string)
 | 
				
			||||||
 | 
					  constructor(board?: Board)
 | 
				
			||||||
 | 
					  constructor(arg1: any) {
 | 
				
			||||||
 | 
					    if (boardSchema.safeParse(arg1).success) {
 | 
				
			||||||
 | 
					      this.board = arg1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else if (typeof arg1 === "string") {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const board = findBoard(arg1)
 | 
				
			||||||
 | 
					        this.board = boardSchema.parse(board)
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        throw new Error("Equipment Construction Failure")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw new Error("Equipment Construction Failure")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  send(header: EquipmentPackage.HeaderOptions) {
 | 
				
			||||||
 | 
					    const pack = new EquipmentPackage.Package(header)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return udpSocketPool.send(pack.toUint8Array(), this.board.port, this.board.ipv4)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // TODO: add params file
 | 
				
			||||||
 | 
					  uploadBitStream() {
 | 
				
			||||||
 | 
					    const header: EquipmentPackage.HeaderOptions = {
 | 
				
			||||||
 | 
					      returnAck: true,
 | 
				
			||||||
 | 
					      transformType: "Extend",
 | 
				
			||||||
 | 
					      readWriteType: "w"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return this.send(header)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,12 @@
 | 
				
			|||||||
import { router, publicProcedure } from "./trpc.ts"
 | 
					import { router, publicProcedure } from "./trpc.ts"
 | 
				
			||||||
 | 
					// import { addUser } from "./database.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const appRouter = router({
 | 
					export const appRouter = router({
 | 
				
			||||||
  api: router({
 | 
					  api: router({
 | 
				
			||||||
    status: publicProcedure.query(() => "OK"),
 | 
					    status: publicProcedure.query(() => "OK"),
 | 
				
			||||||
 | 
					    signUp: publicProcedure.query((opts) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								server/test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								server/test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { allTables } from "./database";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tables = allTables();
 | 
				
			||||||
 | 
					console.log(tables);
 | 
				
			||||||
							
								
								
									
										58
									
								
								server/udp.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								server/udp.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					import type { udp } from "bun"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const udpServer = await Bun.udpSocket({
 | 
				
			||||||
 | 
					  port: 33000,
 | 
				
			||||||
 | 
					  socket: {
 | 
				
			||||||
 | 
					    data(_socket, _buf, _port, _addr) {
 | 
				
			||||||
 | 
					      // todo : Handle Recieved Data
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const udpSocketPool = await createUDPSocketPool(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type bunUDPSocket = udp.Socket<"buffer">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getUDPServerPort() {
 | 
				
			||||||
 | 
					  return udpServer.port
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class UDPSocketPool {
 | 
				
			||||||
 | 
					  freeSockets: Set<bunUDPSocket> = new Set()
 | 
				
			||||||
 | 
					  busySockets: Set<bunUDPSocket> = new Set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getFreeSocket(): bunUDPSocket {
 | 
				
			||||||
 | 
					    const socket = this.freeSockets.values().next().value
 | 
				
			||||||
 | 
					    if (socket !== undefined) {
 | 
				
			||||||
 | 
					      this.busySockets.add(socket)
 | 
				
			||||||
 | 
					      this.freeSockets.delete(socket)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw Error("Failure: Create udp socket failed")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return socket
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  releaseSocket(socket: any) {
 | 
				
			||||||
 | 
					    this.freeSockets.add(socket)
 | 
				
			||||||
 | 
					    this.busySockets.delete(socket)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  send(data: udp.Data, port: number, hostname: string) {
 | 
				
			||||||
 | 
					    const socket = this.getFreeSocket()
 | 
				
			||||||
 | 
					    socket.send(data, port, hostname)
 | 
				
			||||||
 | 
					    this.releaseSocket(socket)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function createUDPSocketPool(depth: number): Promise<UDPSocketPool> {
 | 
				
			||||||
 | 
					  const pool = new UDPSocketPool()
 | 
				
			||||||
 | 
					  for (var i = 0; i < depth; i++) {
 | 
				
			||||||
 | 
					    const socket = await Bun.udpSocket({})
 | 
				
			||||||
 | 
					    pool.freeSockets.add(socket)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return pool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { client } from '@/client';
 | 
					import { client } from '@/client';
 | 
				
			||||||
 | 
					import { TRPCClientError } from '@trpc/client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var bitstream = null;
 | 
					var bitstream = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,9 +42,20 @@ function handleFileChange(event: Event): void {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function uploadBitStream() {
 | 
					async function uploadBitStream() {
 | 
				
			||||||
  const serverStatus = await client.api.status.query();
 | 
					  try {
 | 
				
			||||||
 | 
					    const serverStatus = await client.api.status.query();
 | 
				
			||||||
 | 
					    if (serverStatus != "OK") {
 | 
				
			||||||
 | 
					      throw new Error("Server Busy...")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    if (error instanceof TRPCClientError) {
 | 
				
			||||||
 | 
					      console.error("Can't connect to Server!")
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      console.error(error)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log(serverStatus)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function checkFileType(file: File) {
 | 
					function checkFileType(file: File) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user