mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 19:34:34 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0ffa145bc | ||
|
|
a8df5f4afd | ||
|
|
62de960e86 | ||
|
|
31532c0efa | ||
|
|
732230524d | ||
|
|
6dc281313e | ||
|
|
92db3c7c82 | ||
|
|
d8b75a47d3 | ||
|
|
d70fc1032f | ||
|
|
794ee8f6e0 | ||
|
|
43769e711d | ||
|
|
30528a1528 | ||
|
|
b7e1753d25 | ||
|
|
9c5772a303 | ||
|
|
7a3d710153 | ||
|
|
0a6ebe6e62 | ||
|
|
6cbc657da3 | ||
|
|
cd838915fd |
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -32,10 +32,17 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
|
- name: Compress Executables
|
||||||
|
working-directory: ./executables
|
||||||
|
run: |
|
||||||
|
zip linux.zip api-linux
|
||||||
|
zip macos.zip api-macos
|
||||||
|
zip windows.zip api-win.exe
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
./executables/api-linux
|
./executables/linux.zip
|
||||||
./executables/api-macos
|
./executables/macos.zip
|
||||||
./executables/api-win.exe
|
./executables/windows.zip
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -2,6 +2,36 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.0.19](https://github.com/sasjs/server/compare/v0.0.18...v0.0.19) (2022-01-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bumping sasjs/core and updating descriptions ([31532c0](https://github.com/sasjs/server/commit/31532c0efa41e53f87377a2c7c41d21c7909e3a0))
|
||||||
|
|
||||||
|
### [0.0.18](https://github.com/sasjs/server/compare/v0.0.17...v0.0.18) (2022-01-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* compressing release files for faster download times ([d8b75a4](https://github.com/sasjs/server/commit/d8b75a47d305e0772ccbf8837ba4d7347b94cc93))
|
||||||
|
|
||||||
|
### [0.0.17](https://github.com/sasjs/server/compare/v0.0.16...v0.0.17) (2022-01-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bug removed, log is clean now ([43769e7](https://github.com/sasjs/server/commit/43769e711d37a4f670786545630139a2d926dc76))
|
||||||
|
|
||||||
|
### [0.0.16](https://github.com/sasjs/server/compare/v0.0.15...v0.0.16) (2022-01-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* added sas9 server address ([cd83891](https://github.com/sasjs/server/commit/cd838915fdb216ee364ea677747409311b1214fb))
|
||||||
|
* recreate crashed session ([6cbc657](https://github.com/sasjs/server/commit/6cbc657da3eb7fa821a678443a3ae4079c2a1f09))
|
||||||
|
* session should be marked as consumed ([7a3d710](https://github.com/sasjs/server/commit/7a3d710153f37d12160ff45f8f97fb4fcc75d684))
|
||||||
|
|
||||||
### [0.0.15](https://github.com/sasjs/server/compare/v0.0.14...v0.0.15) (2022-01-06)
|
### [0.0.15](https://github.com/sasjs/server/compare/v0.0.14...v0.0.15) (2022-01-06)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -10,7 +10,15 @@ One major benefit of using SASjs Server (alongside other components of the SASjs
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Just download the relevant package from the [releases](https://github.com/sasjs/server/releases) page and trigger, either by double clicking (windows) or executing from commandline.
|
First, download the relevant package from the [releases](https://github.com/sasjs/server/releases) page - either manually, or with commandline, eg as follow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -L https://github.com/sasjs/server/releases/latest/download/linux.zip > linux.zip
|
||||||
|
unzip linux.zip
|
||||||
|
./api-linux
|
||||||
|
```
|
||||||
|
|
||||||
|
Second, trigger by double clicking (windows) or executing from commandline.
|
||||||
|
|
||||||
You are presented with two prompts:
|
You are presented with two prompts:
|
||||||
|
|
||||||
|
|||||||
10
api/CHANGELOG.md
Normal file
10
api/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.0.2](https://github.com/sasjs/server/compare/v0.0.19...v0.0.2) (2022-01-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bumping core version ([a8df5f4](https://github.com/sasjs/server/commit/a8df5f4afd6c4522270d0a60ab8153dfbdf79e16))
|
||||||
1161
api/package-lock.json
generated
1161
api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "api",
|
"name": "api",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "Api of SASjs server",
|
"description": "Api of SASjs server",
|
||||||
"main": "./src/server.ts",
|
"main": "./src/server.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -44,9 +44,9 @@
|
|||||||
"main"
|
"main"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"author": "Analytium Ltd",
|
"author": "4GL Ltd",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "^3.0.2",
|
"@sasjs/core": "3.11.1",
|
||||||
"@sasjs/utils": "2.34.1",
|
"@sasjs/utils": "2.34.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
@@ -88,4 +88,4 @@
|
|||||||
"configuration": {
|
"configuration": {
|
||||||
"sasPath": "/opt/sas/sas9/SASHome/SASFoundation/9.4/sas"
|
"sasPath": "/opt/sas/sas9/SASHome/SASFoundation/9.4/sas"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ info:
|
|||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
description: 'Api of SASjs server'
|
description: 'Api of SASjs server'
|
||||||
contact:
|
contact:
|
||||||
name: 'Analytium Ltd'
|
name: '4GL Ltd'
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
paths:
|
paths:
|
||||||
/SASjsApi/auth/authorize:
|
/SASjsApi/auth/authorize:
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ dotenv.config()
|
|||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
const { MODE, CORS, PORT_WEB } = process.env
|
const { MODE, CORS, PORT_WEB } = process.env
|
||||||
|
const whiteList = [
|
||||||
|
`http://localhost:${PORT_WEB ?? 3000}`,
|
||||||
|
'https://sas.analytium.co.uk:8343'
|
||||||
|
]
|
||||||
|
|
||||||
if (MODE?.trim() !== 'server' || CORS?.trim() === 'enable') {
|
if (MODE?.trim() !== 'server' || CORS?.trim() === 'enable') {
|
||||||
console.log('All CORS Requests are enabled')
|
console.log('All CORS Requests are enabled')
|
||||||
app.use(
|
app.use(cors({ credentials: true, origin: whiteList }))
|
||||||
cors({ credentials: true, origin: `http://localhost:${PORT_WEB ?? 3000}` })
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(express.json({ limit: '50mb' }))
|
app.use(express.json({ limit: '50mb' }))
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export class ExecutionController {
|
|||||||
|
|
||||||
const session = await sessionController.getSession()
|
const session = await sessionController.getSession()
|
||||||
session.inUse = true
|
session.inUse = true
|
||||||
|
session.consumed = true
|
||||||
|
|
||||||
const logPath = path.join(session.path, 'log.log')
|
const logPath = path.join(session.path, 'log.log')
|
||||||
|
|
||||||
@@ -100,14 +101,12 @@ ${program}`
|
|||||||
await createFile(codePath + '.bkp', program)
|
await createFile(codePath + '.bkp', program)
|
||||||
await moveFile(codePath + '.bkp', codePath)
|
await moveFile(codePath + '.bkp', codePath)
|
||||||
|
|
||||||
// we now need to poll the session array
|
// we now need to poll the session status
|
||||||
while (!session.completed) {
|
while (!session.completed) {
|
||||||
await delay(50)
|
await delay(50)
|
||||||
}
|
}
|
||||||
|
|
||||||
const log =
|
const log = (await fileExists(logPath)) ? await readFile(logPath) : ''
|
||||||
((await fileExists(logPath)) ? await readFile(logPath) : '') +
|
|
||||||
session.crashed
|
|
||||||
const webout = (await fileExists(weboutPath))
|
const webout = (await fileExists(weboutPath))
|
||||||
? await readFile(weboutPath)
|
? await readFile(weboutPath)
|
||||||
: ''
|
: ''
|
||||||
@@ -115,8 +114,8 @@ ${program}`
|
|||||||
const debugValue =
|
const debugValue =
|
||||||
typeof vars._debug === 'string' ? parseInt(vars._debug) : vars._debug
|
typeof vars._debug === 'string' ? parseInt(vars._debug) : vars._debug
|
||||||
|
|
||||||
|
// it should be deleted by scheduleSessionDestroy
|
||||||
session.inUse = false
|
session.inUse = false
|
||||||
sessionController.deleteSession(session)
|
|
||||||
|
|
||||||
if (returnJson) {
|
if (returnJson) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import {
|
|||||||
createFile,
|
createFile,
|
||||||
fileExists,
|
fileExists,
|
||||||
generateTimestamp,
|
generateTimestamp,
|
||||||
readFile
|
readFile,
|
||||||
|
moveFile
|
||||||
} from '@sasjs/utils'
|
} from '@sasjs/utils'
|
||||||
|
|
||||||
const execFilePromise = promisify(execFile)
|
const execFilePromise = promisify(execFile)
|
||||||
@@ -20,8 +21,11 @@ const execFilePromise = promisify(execFile)
|
|||||||
export class SessionController {
|
export class SessionController {
|
||||||
private sessions: Session[] = []
|
private sessions: Session[] = []
|
||||||
|
|
||||||
|
private getReadySessions = (): Session[] =>
|
||||||
|
this.sessions.filter((sess: Session) => sess.ready && !sess.consumed)
|
||||||
|
|
||||||
public async getSession() {
|
public async getSession() {
|
||||||
const readySessions = this.sessions.filter((sess: Session) => sess.ready)
|
const readySessions = this.getReadySessions()
|
||||||
|
|
||||||
const session = readySessions.length
|
const session = readySessions.length
|
||||||
? readySessions[0]
|
? readySessions[0]
|
||||||
@@ -32,8 +36,9 @@ export class SessionController {
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSession() {
|
private async createSession(): Promise<Session> {
|
||||||
const sessionId = generateUniqueFileName(generateTimestamp())
|
const sessionId = generateUniqueFileName(generateTimestamp())
|
||||||
|
console.log('creating session', sessionId)
|
||||||
const sessionFolder = path.join(getTmpSessionsFolderPath(), sessionId)
|
const sessionFolder = path.join(getTmpSessionsFolderPath(), sessionId)
|
||||||
|
|
||||||
const creationTimeStamp = sessionId.split('-').pop() as string
|
const creationTimeStamp = sessionId.split('-').pop() as string
|
||||||
@@ -47,6 +52,7 @@ export class SessionController {
|
|||||||
id: sessionId,
|
id: sessionId,
|
||||||
ready: false,
|
ready: false,
|
||||||
inUse: false,
|
inUse: false,
|
||||||
|
consumed: false,
|
||||||
completed: false,
|
completed: false,
|
||||||
creationTimeStamp,
|
creationTimeStamp,
|
||||||
deathTimeStamp,
|
deathTimeStamp,
|
||||||
@@ -105,15 +111,16 @@ export class SessionController {
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
public async waitForSession(session: Session) {
|
private async waitForSession(session: Session) {
|
||||||
const codeFilePath = path.join(session.path, 'code.sas')
|
const codeFilePath = path.join(session.path, 'code.sas')
|
||||||
|
|
||||||
// TODO: don't wait forever
|
// TODO: don't wait forever
|
||||||
while ((await fileExists(codeFilePath)) && !session.crashed) {}
|
while ((await fileExists(codeFilePath)) && !session.crashed) {}
|
||||||
console.log('session crashed?', !!session.crashed, session.crashed || '')
|
|
||||||
|
if (session.crashed)
|
||||||
|
console.log('session crashed! while waiting to be ready', session.crashed)
|
||||||
|
|
||||||
session.ready = true
|
session.ready = true
|
||||||
return Promise.resolve(session)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deleteSession(session: Session) {
|
public async deleteSession(session: Session) {
|
||||||
@@ -121,11 +128,9 @@ export class SessionController {
|
|||||||
await deleteFolder(session.path)
|
await deleteFolder(session.path)
|
||||||
|
|
||||||
// remove the session from the session array
|
// remove the session from the session array
|
||||||
if (session.ready) {
|
this.sessions = this.sessions.filter(
|
||||||
this.sessions = this.sessions.filter(
|
(sess: Session) => sess.id !== session.id
|
||||||
(sess: Session) => sess.id !== session.id
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private scheduleSessionDestroy(session: Session) {
|
private scheduleSessionDestroy(session: Session) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export interface Session {
|
|||||||
deathTimeStamp: string
|
deathTimeStamp: string
|
||||||
path: string
|
path: string
|
||||||
inUse: boolean
|
inUse: boolean
|
||||||
|
consumed: boolean
|
||||||
completed: boolean
|
completed: boolean
|
||||||
crashed?: string
|
crashed?: string
|
||||||
}
|
}
|
||||||
|
|||||||
1575
package-lock.json
generated
1575
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.15",
|
"version": "0.0.19",
|
||||||
"description": "NodeJS wrapper for calling the SAS binary executable",
|
"description": "NodeJS wrapper for calling the SAS binary executable",
|
||||||
"repository": "https://github.com/sasjs/server",
|
"repository": "https://github.com/sasjs/server",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user