mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 19:34:34 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c872bde92 | ||
|
|
f953472efd | ||
|
|
f10138b0f2 | ||
|
|
6f19d3d0ea | ||
|
|
a7facb005a | ||
|
|
88acf9df5d | ||
|
|
b0880b142a | ||
|
|
d3674c7f94 | ||
|
|
adccca6c7f | ||
|
|
8b83ccc4c2 | ||
|
|
556944b1d5 | ||
|
|
fde4bc051d | ||
|
|
f2000a1227 | ||
|
|
bf5767eadf |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -2,6 +2,26 @@
|
|||||||
|
|
||||||
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.28](https://github.com/sasjs/server/compare/v0.0.27...v0.0.28) (2022-02-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* default macros and bumping core ([6f19d3d](https://github.com/sasjs/server/commit/6f19d3d0ea3815815f246a3e455495c72c8604c7))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* moving core ([f10138b](https://github.com/sasjs/server/commit/f10138b0f2005a958f63cb3a8351e1afa52f086a))
|
||||||
|
|
||||||
|
### [0.0.27](https://github.com/sasjs/server/compare/v0.0.26...v0.0.27) (2022-02-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* removing stpsrv_header and updating README with auth details ([d3674c7](https://github.com/sasjs/server/commit/d3674c7f9449d77977e482cd63ccdf7e974fa838))
|
||||||
|
* **stp-execution:** add returnLog option to execution query ([bf5767e](https://github.com/sasjs/server/commit/bf5767eadfb87f7ed902659347a18361a6a6c74b))
|
||||||
|
|
||||||
### [0.0.26](https://github.com/sasjs/server/compare/v0.0.25...v0.0.26) (2022-02-14)
|
### [0.0.26](https://github.com/sasjs/server/compare/v0.0.25...v0.0.26) (2022-02-14)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
README.md
43
README.md
@@ -9,18 +9,19 @@ SASjs Server provides a NodeJS wrapper for calling the SAS binary executable. It
|
|||||||
One major benefit of using SASjs Server (alongside other components of the SASjs framework such as the [CLI](https://cli.sasjs.io), [Adapter](https://adapter.sasjs.io) and [Core](https://core.sasjs.io) library) is that the projects you create can be very easily ported to SAS 9 (Stored Process server) or Viya (Job Execution server).
|
One major benefit of using SASjs Server (alongside other components of the SASjs framework such as the [CLI](https://cli.sasjs.io), [Adapter](https://adapter.sasjs.io) and [Core](https://core.sasjs.io) library) is that the projects you create can be very easily ported to SAS 9 (Stored Process server) or Viya (Job Execution server).
|
||||||
|
|
||||||
SASjs Server is available in two modes - Desktop (without authentication) and Server (with authentiation, and a database)
|
SASjs Server is available in two modes - Desktop (without authentication) and Server (with authentiation, and a database)
|
||||||
|
|
||||||
## Desktop Version
|
## Desktop Version
|
||||||
|
|
||||||
### Manual Installation
|
### Manual Installation
|
||||||
|
|
||||||
Download the relevant package from the [releases](https://github.com/sasjs/server/releases) page
|
Download the relevant package from the [releases](https://github.com/sasjs/server/releases) page
|
||||||
|
|
||||||
Next, trigger by double clicking (windows) or executing from commandline.
|
Next, trigger by double clicking (windows) or executing from commandline.
|
||||||
|
|
||||||
You are presented with two prompts:
|
You are presented with two prompts:
|
||||||
|
|
||||||
* Location of your `sas.exe` / `sas.sh` executable
|
- Location of your `sas.exe` / `sas.sh` executable
|
||||||
* Path to a filesystem location for Stored Programs and temporary files
|
- Path to a filesystem location for Stored Programs and temporary files
|
||||||
|
|
||||||
|
|
||||||
## Programmatic Installation
|
## Programmatic Installation
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ unzip linux.zip
|
|||||||
|
|
||||||
The app can then be launched with `./api-linux` and prompts followed.
|
The app can then be launched with `./api-linux` and prompts followed.
|
||||||
|
|
||||||
When launching the app, it will make use of specific environment variables. These can be set in the following places:
|
When launching the app, it will make use of specific environment variables. These can be set in the following places:
|
||||||
|
|
||||||
- Configured globally in /etc/environment file
|
- Configured globally in /etc/environment file
|
||||||
- Export in terminal or shell script (`export VAR=VALUE`)
|
- Export in terminal or shell script (`export VAR=VALUE`)
|
||||||
@@ -50,26 +51,44 @@ DRIVE_PATH=./tmp
|
|||||||
|
|
||||||
Setting these prompts variables will avoid the need for prompts.
|
Setting these prompts variables will avoid the need for prompts.
|
||||||
|
|
||||||
Normally the server process will stop when your terminal dies. To keep it going you can use the npm package [forever](https://www.npmjs.com/package/forever) (`npm i -g forever`) as follows:
|
Normally the server process will stop when your terminal dies. To keep it going you can use the npm package [pm2](https://www.npmjs.com/package/pm2) (`npm install pm2@latest -g`) as follows:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
|
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
|
||||||
export PORT=5001
|
export PORT=5001
|
||||||
export DRIVE_PATH=./tmp
|
export DRIVE_PATH=./tmp
|
||||||
|
|
||||||
forever start -c "./api-linux" ./
|
pm2 start api-linux
|
||||||
```
|
```
|
||||||
|
|
||||||
To get the log files:
|
To get the logs (and some usefull commands):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
forever list
|
pm2 [list|ls|status]
|
||||||
# grap log file link
|
pm2 logs
|
||||||
tail -f LOGFILE
|
pm2 logs --lines 200
|
||||||
```
|
```
|
||||||
|
|
||||||
To stop:
|
Managing processes:
|
||||||
|
|
||||||
```
|
```
|
||||||
forever stop <pid>
|
pm2 restart app_name
|
||||||
|
pm2 reload app_name
|
||||||
|
pm2 stop app_name
|
||||||
|
pm2 delete app_name
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Instead of `app_name` you can pass:
|
||||||
|
|
||||||
|
- `all` to act on all processes
|
||||||
|
- `id` to act on a specific process id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Server Version
|
||||||
|
|
||||||
|
The following credentials can be used for the initial connection to SASjs/server. It is recommended to change these on first use.
|
||||||
|
|
||||||
|
* CLIENTID: `clientID1`
|
||||||
|
* USERNAME: `secretuser`
|
||||||
|
* PASSWORD: `secretpassword`
|
||||||
|
|||||||
14
api/package-lock.json
generated
14
api/package-lock.json
generated
@@ -8,7 +8,7 @@
|
|||||||
"name": "api",
|
"name": "api",
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "4.8.0",
|
"@sasjs/core": "4.9.0",
|
||||||
"@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",
|
||||||
@@ -1418,9 +1418,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/core": {
|
"node_modules/@sasjs/core": {
|
||||||
"version": "4.8.0",
|
"version": "4.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.9.0.tgz",
|
||||||
"integrity": "sha512-go31UvPRzOqWJm2hkM+9/KQXIky9SA7bFMLa2d1dMfpdrX0XQyw+dcDM3jHD/agtcATWYJ9exJrET7Bkj148YQ=="
|
"integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/utils": {
|
"node_modules/@sasjs/utils": {
|
||||||
"version": "2.34.1",
|
"version": "2.34.1",
|
||||||
@@ -11132,9 +11132,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sasjs/core": {
|
"@sasjs/core": {
|
||||||
"version": "4.8.0",
|
"version": "4.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.9.0.tgz",
|
||||||
"integrity": "sha512-go31UvPRzOqWJm2hkM+9/KQXIky9SA7bFMLa2d1dMfpdrX0XQyw+dcDM3jHD/agtcATWYJ9exJrET7Bkj148YQ=="
|
"integrity": "sha512-zc1Ey0ylHt/eRZAfK0mVG3EqNyq//wLxbiguiK0R6FhVqwYFEkprs3IiLGZ5M9ttKs2rHRIjOe/ckklHm+6HNQ=="
|
||||||
},
|
},
|
||||||
"@sasjs/utils": {
|
"@sasjs/utils": {
|
||||||
"version": "2.34.1",
|
"version": "2.34.1",
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
},
|
},
|
||||||
"author": "4GL Ltd",
|
"author": "4GL Ltd",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "4.8.0",
|
"@sasjs/core": "4.9.0",
|
||||||
"@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",
|
||||||
|
|||||||
@@ -4,10 +4,24 @@
|
|||||||
@details This program is inserted into every sasjs/server program invocation,
|
@details This program is inserted into every sasjs/server program invocation,
|
||||||
_before_ any user-provided content.
|
_before_ any user-provided content.
|
||||||
|
|
||||||
|
A number of useful CORE macros are also compiled below, so that they can be
|
||||||
|
available "out of the box".
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mcf_stpsrv_header.sas
|
@li mcf_stpsrv_header.sas
|
||||||
|
@li mf_getuser.sas
|
||||||
|
@li mf_getvarlist.sas
|
||||||
|
@li mf_mkdir.sas
|
||||||
|
@li mf_nobs.sas
|
||||||
|
@li mf_uid.sas
|
||||||
|
@li mfs_httpheader.sas
|
||||||
|
@li mp_dirlist.sas
|
||||||
|
@li mp_ds2ddl.sas
|
||||||
|
@li mp_ds2md.sas
|
||||||
|
@li mp_getdbml.sas
|
||||||
|
@li mp_init.sas
|
||||||
|
@li mp_makedata.sas
|
||||||
|
@li mp_zip.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
|
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class DriveController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getFileTree = () => {
|
const getFileTree = () => {
|
||||||
const tree = new ExecutionController().buildDirectorytree()
|
const tree = new ExecutionController().buildDirectoryTree()
|
||||||
return { status: 'success', tree }
|
return { status: 'success', tree }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ import { readFile, fileExists, createFile, moveFile } from '@sasjs/utils'
|
|||||||
import { PreProgramVars, TreeNode } from '../../types'
|
import { PreProgramVars, TreeNode } from '../../types'
|
||||||
import { generateFileUploadSasCode, getTmpFilesFolderPath } from '../../utils'
|
import { generateFileUploadSasCode, getTmpFilesFolderPath } from '../../utils'
|
||||||
|
|
||||||
|
export interface ExecutionVars {
|
||||||
|
[key: string]: string | number | undefined
|
||||||
|
}
|
||||||
|
|
||||||
export class ExecutionController {
|
export class ExecutionController {
|
||||||
async executeFile(
|
async executeFile(
|
||||||
programPath: string,
|
programPath: string,
|
||||||
preProgramVariables: PreProgramVars,
|
preProgramVariables: PreProgramVars,
|
||||||
vars: { [key: string]: string | number | undefined },
|
vars: ExecutionVars,
|
||||||
otherArgs?: any,
|
otherArgs?: any,
|
||||||
returnJson?: boolean
|
returnJson?: boolean
|
||||||
) {
|
) {
|
||||||
@@ -29,7 +33,7 @@ export class ExecutionController {
|
|||||||
async executeProgram(
|
async executeProgram(
|
||||||
program: string,
|
program: string,
|
||||||
preProgramVariables: PreProgramVars,
|
preProgramVariables: PreProgramVars,
|
||||||
vars: { [key: string]: string | number | undefined },
|
vars: ExecutionVars,
|
||||||
otherArgs?: any,
|
otherArgs?: any,
|
||||||
returnJson?: boolean
|
returnJson?: boolean
|
||||||
) {
|
) {
|
||||||
@@ -55,6 +59,7 @@ export class ExecutionController {
|
|||||||
`${computed}%let ${key}=${vars[key]};\n`,
|
`${computed}%let ${key}=${vars[key]};\n`,
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
|
|
||||||
const preProgramVarStatments = `
|
const preProgramVarStatments = `
|
||||||
%let _sasjs_tokenfile=${tokenFile};
|
%let _sasjs_tokenfile=${tokenFile};
|
||||||
%let _sasjs_username=${preProgramVariables?.username};
|
%let _sasjs_username=${preProgramVariables?.username};
|
||||||
@@ -138,7 +143,7 @@ ${program}`
|
|||||||
: webout
|
: webout
|
||||||
}
|
}
|
||||||
|
|
||||||
buildDirectorytree() {
|
buildDirectoryTree() {
|
||||||
const root: TreeNode = {
|
const root: TreeNode = {
|
||||||
name: 'files',
|
name: 'files',
|
||||||
relativePath: '',
|
relativePath: '',
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class FileUploadController {
|
|||||||
|
|
||||||
//It will intercept request and generate unique uuid to be used as a subfolder name
|
//It will intercept request and generate unique uuid to be used as a subfolder name
|
||||||
//that will store the files uploaded
|
//that will store the files uploaded
|
||||||
public preuploadMiddleware = async (req: any, res: any, next: any) => {
|
public preUploadMiddleware = async (req: any, res: any, next: any) => {
|
||||||
let session
|
let session
|
||||||
|
|
||||||
const sessionController = getSessionController()
|
const sessionController = getSessionController()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa'
|
import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa'
|
||||||
import { ExecutionController } from './internal'
|
import { ExecutionController, ExecutionVars } from './internal'
|
||||||
import { PreProgramVars } from '../types'
|
import { PreProgramVars } from '../types'
|
||||||
import { getTmpFilesFolderPath, makeFilesNamesMap } from '../utils'
|
import { getTmpFilesFolderPath, makeFilesNamesMap } from '../utils'
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ const executeReturnRaw = async (
|
|||||||
req: express.Request,
|
req: express.Request,
|
||||||
_program: string
|
_program: string
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
const query = req.query as { [key: string]: string | number | undefined }
|
const query = req.query as ExecutionVars
|
||||||
const sasCodePath =
|
const sasCodePath =
|
||||||
path
|
path
|
||||||
.join(getTmpFilesFolderPath(), _program)
|
.join(getTmpFilesFolderPath(), _program)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { SessionController } from '../../controllers'
|
import { SessionController } from '../../controllers'
|
||||||
import { authenticateAccessToken } from '../../middlewares'
|
|
||||||
|
|
||||||
const sessionRouter = express.Router()
|
const sessionRouter = express.Router()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { executeProgramRawValidation, runSASValidation } from '../../utils'
|
import { executeProgramRawValidation } from '../../utils'
|
||||||
import { STPController } from '../../controllers/'
|
import { STPController } from '../../controllers/'
|
||||||
import { FileUploadController } from '../../controllers/internal'
|
import { FileUploadController } from '../../controllers/internal'
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ stpRouter.get('/execute', async (req, res) => {
|
|||||||
|
|
||||||
stpRouter.post(
|
stpRouter.post(
|
||||||
'/execute',
|
'/execute',
|
||||||
fileUploadController.preuploadMiddleware,
|
fileUploadController.preUploadMiddleware,
|
||||||
fileUploadController.getMulterUploadObject().any(),
|
fileUploadController.getMulterUploadObject().any(),
|
||||||
async (req: any, res: any) => {
|
async (req: any, res: any) => {
|
||||||
const { error: errQ, value: query } = executeProgramRawValidation(req.query)
|
const { error: errQ, value: query } = executeProgramRawValidation(req.query)
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.26",
|
"version": "0.0.28",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.26",
|
"version": "0.0.28",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"standard-version": "^9.3.2"
|
"standard-version": "^9.3.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.26",
|
"version": "0.0.28",
|
||||||
"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