1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 19:34:34 +00:00

Compare commits

...

39 Commits

Author SHA1 Message Date
munja
bee5deed2a chore(release): 0.0.25 2022-02-11 17:30:39 +01:00
Muhammad Saad
e6e46838b3 Merge pull request #53 from sasjs/corebump
fix: adding global macvar and bumping sasjs/core with additional server support
2022-02-11 20:28:16 +04:00
munja
404f1ec059 fix: adding global macvar and bumping sasjs/core with additional server support 2022-02-11 17:24:55 +01:00
munja
09d36bc754 chore(release): 0.0.24 2022-02-11 12:53:06 +01:00
Muhammad Saad
3722bbaec3 Merge pull request #52 from sasjs/forever
chore(readme): forever package
2022-02-11 15:43:23 +04:00
munja
480ee4da83 fix: removing sysmacdelete 2022-02-11 12:11:34 +01:00
munja
dd853fe13b chore(docs): adding contributing 2022-02-11 12:05:05 +01:00
munja
e1142a33a0 chore: automated commit 2022-02-11 11:27:47 +01:00
munja
d4e8d91cae chore(readme): forever package 2022-02-11 10:47:40 +01:00
Saad Jutt
9a74ec545d chore: docker fix for SAS executable 2022-02-11 14:30:25 +05:00
Saad Jutt
e3f5206758 chore(release): 0.0.23 2022-02-08 21:46:00 +05:00
Saad Jutt
fffd21b348 chore: quick fixes 2022-02-08 21:45:56 +05:00
Saad Jutt
2d74ef5e12 chore(release): 0.0.22 2022-02-08 21:45:41 +05:00
munja
224743a439 Merge branch 'main' of github.com:sasjs/server 2022-02-01 15:19:56 +01:00
munja
f39a76da17 chore(release): 0.0.21 2022-02-01 15:19:36 +01:00
Allan Bowe
6107d02c8e Merge pull request #49 from sasjs/autoexecfix
fix: adding missing global vars to autoexec
2022-02-01 16:18:38 +02:00
munja
1966b17f27 fix: adding missing global vars to autoexec 2022-02-01 15:14:31 +01:00
Allan Bowe
87c8aa5146 Merge pull request #47 from sasjs/fixnot
fix: avoid uninitialised note
2022-01-26 18:30:21 +02:00
munja
e4c027ad51 fix: avoid uninitialised note 2022-01-26 17:27:08 +01:00
munja
083355fdba chore(release): 0.0.20 2022-01-20 14:03:05 +01:00
munja
a3b57f6e28 fix: fixing versioning blooper 2022-01-20 14:03:00 +01:00
munja
b0ffa145bc chore(release): 0.0.2 2022-01-20 13:57:35 +01:00
munja
a8df5f4afd fix: bumping core version 2022-01-20 13:57:31 +01:00
munja
62de960e86 chore(release): 0.0.19 2022-01-20 10:39:34 +01:00
munja
31532c0efa fix: bumping sasjs/core and updating descriptions 2022-01-20 10:37:22 +01:00
Allan Bowe
732230524d Merge pull request #46 from sasjs/allanbowe-patch-1
Update README.md
2022-01-20 11:06:25 +02:00
Allan Bowe
6dc281313e Update README.md 2022-01-19 22:34:41 +00:00
munja
92db3c7c82 chore(release): 0.0.18 2022-01-08 20:24:57 +01:00
munja
d8b75a47d3 fix: compressing release files for faster download times 2022-01-08 20:22:22 +01:00
Saad Jutt
d70fc1032f chore(release): 0.0.17 2022-01-08 02:15:38 +05:00
Muhammad Saad
794ee8f6e0 Merge pull request #45 from sasjs/hot-fix
fix: bug removed, log is clean now
2022-01-08 01:11:04 +04:00
Saad Jutt
43769e711d fix: bug removed, log is clean now 2022-01-08 00:42:32 +05:00
Saad Jutt
30528a1528 chore(release): 0.0.16 2022-01-07 16:47:01 +05:00
Muhammad Saad
b7e1753d25 Merge pull request #44 from sasjs/cors-update
Cors update
2022-01-07 15:46:24 +04:00
Saad Jutt
9c5772a303 chore: clean up 2022-01-07 16:42:38 +05:00
Saad Jutt
7a3d710153 fix: session should be marked as consumed 2022-01-07 16:34:46 +05:00
Saad Jutt
0a6ebe6e62 chore: debugging 2022-01-07 15:38:11 +05:00
Saad Jutt
6cbc657da3 fix: recreate crashed session 2022-01-06 23:12:44 +05:00
Saad Jutt
cd838915fd fix: added sas9 server address 2022-01-06 18:40:23 +05:00
17 changed files with 452 additions and 1212 deletions

View File

@@ -1,4 +1,5 @@
SAS_EXEC=<path to folder containing SAS executable 'sas'> SAS_EXEC_PATH=<path to folder containing SAS executable>
SAS_EXEC_NAME=<name of SAS executable file>
PORT_API=<port for sasjs server (api)> PORT_API=<port for sasjs server (api)>
PORT_WEB=<port for sasjs web component(react)> PORT_WEB=<port for sasjs web component(react)>
ACCESS_TOKEN_SECRET=<secret> ACCESS_TOKEN_SECRET=<secret>

115
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,115 @@
# CONTRIBUTING
Contributions are very welcome! Feel free to raise an issue or start a discussion, for help in getting started.
## Configuration
Configuration is made in the `configuration` section of `package.json`:
- Provide path to SAS9 executable.
### Using dockers:
There is `.env.example` file present at root of the project. [for Production]
There is `.env.example` file present at `./api` of the project. [for Development]
There is `.env.example` file present at `./web` of the project. [for Development]
Remember to provide enviornment variables.
#### Development
Command to run docker for development:
```
docker-compose up -d
```
It uses default docker compose file i.e. `docker-compose.yml` present at root.
It will build following images if running first time:
- `sasjs_server_api` - image for sasjs api server app based on _ExpressJS_
- `sasjs_server_web` - image for sasjs web component app based on _ReactJS_
- `mongodb` - image for mongo database
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
#### Production
Command to run docker for production:
```
docker-compose -f docker-compose.prod.yml up -d
```
It uses specified docker compose file i.e. `docker-compose.prod.yml` present at root.
It will build following images if running first time:
- `sasjs_server_prod` - image for sasjs server app containing api and web component's build served at route `/`
- `mongodb` - image for mongo database
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
### Using node:
#### Development (running api and web seperately):
##### API
Navigate to `./api`
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
Command to install and run api server.
```
npm install
npm start
```
##### Web
Navigate to `./web`
There is `.env.example` file present at `./web` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
Command to install and run api server.
```
npm install
npm start
```
#### Development (running only api server and have web build served):
##### API server also serving Web build files
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
Command to install and run api server.
```
cd ./web && npm i && npm build && cd ../
cd ./api && npm i && npm start
```
#### Production
##### API & WEB
```
npm run server
```
This will install/build `web` and install `api`, then start prod server.
## Executables
Command to generate executables
```
cd ./web && npm i && npm build && cd ../
cd ./api && npm i && npm run exe
```
This will install/build web app and install/create executables of sasjs server at root `./executables`

View File

@@ -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

View File

@@ -2,6 +2,78 @@
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.25](https://github.com/sasjs/server/compare/v0.0.24...v0.0.25) (2022-02-11)
### Bug Fixes
* adding global macvar and bumping sasjs/core with additional server support ([404f1ec](https://github.com/sasjs/server/commit/404f1ec0593a027ed5e84b1d6a84cb9f2d09d99e))
### [0.0.24](https://github.com/sasjs/server/compare/v0.0.23...v0.0.24) (2022-02-11)
### Bug Fixes
* removing sysmacdelete ([480ee4d](https://github.com/sasjs/server/commit/480ee4da831d2a89888c58ebec26bd89802ee2f5))
### [0.0.23](https://github.com/sasjs/server/compare/v0.0.22...v0.0.23) (2022-02-08)
### [0.0.22](https://github.com/sasjs/server/compare/v0.0.17...v0.0.22) (2022-02-08)
### Bug Fixes
* adding missing global vars to autoexec ([1966b17](https://github.com/sasjs/server/commit/1966b17f27e66bf1c9673ef6e1c11f4868b4f816))
* avoid uninitialised note ([e4c027a](https://github.com/sasjs/server/commit/e4c027ad5121302b9ae093b2b76dc27f51a94365))
* bumping core version ([a8df5f4](https://github.com/sasjs/server/commit/a8df5f4afd6c4522270d0a60ab8153dfbdf79e16))
* bumping sasjs/core and updating descriptions ([31532c0](https://github.com/sasjs/server/commit/31532c0efa41e53f87377a2c7c41d21c7909e3a0))
* compressing release files for faster download times ([d8b75a4](https://github.com/sasjs/server/commit/d8b75a47d305e0772ccbf8837ba4d7347b94cc93))
* fixing versioning blooper ([a3b57f6](https://github.com/sasjs/server/commit/a3b57f6e28448fe98e634383041a5633541c8c02))
### [0.0.21](https://github.com/sasjs/server/compare/v0.0.20...v0.0.21) (2022-02-01)
### Bug Fixes
* avoid uninitialised note ([e4c027a](https://github.com/sasjs/server/commit/e4c027ad5121302b9ae093b2b76dc27f51a94365))
### [0.0.20](https://github.com/sasjs/server/compare/v0.0.2...v0.0.20) (2022-01-20)
### Bug Fixes
* fixing versioning blooper ([a3b57f6](https://github.com/sasjs/server/commit/a3b57f6e28448fe98e634383041a5633541c8c02))
### [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)

121
README.md
View File

@@ -8,119 +8,68 @@ 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).
## Installation SASjs Server is available in two modes - Desktop (without authentication) and Server (with authentiation, and a database)
## Desktop Version
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. ### Manual Installation
Download the relevant package from the [releases](https://github.com/sasjs/server/releases) page
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
## Configuration
Configuration is made in the `configuration` section of `package.json`: ## Programmatic Installation
- Provide path to SAS9 executable. Fetch the relevant package from github using `curl`, eg as follows (for linux):
### Using dockers: ```bash
curl -L https://github.com/sasjs/server/releases/latest/download/linux.zip > linux.zip
There is `.env.example` file present at root of the project. [for Production] unzip linux.zip
There is `.env.example` file present at `./api` of the project. [for Development]
There is `.env.example` file present at `./web` of the project. [for Development]
Remember to provide enviornment variables.
#### Development
Command to run docker for development:
```
docker-compose up -d
``` ```
It uses default docker compose file i.e. `docker-compose.yml` present at root. The app can then be launched with `./api-linux` and prompts followed.
It will build following images if running first time:
- `sasjs_server_api` - image for sasjs api server app based on _ExpressJS_ When launching the app, it will make use of specific environment variables. These can be set in the following places:
- `sasjs_server_web` - image for sasjs web component app based on _ReactJS_
- `mongodb` - image for mongo database
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
#### Production - Configured globally in /etc/environment file
- Export in terminal or shell script (`export VAR=VALUE`)
- Prepend in command
- Enter in the `.env` file alongside the executable
Command to run docker for production: Example variables:
``` ```
docker-compose -f docker-compose.prod.yml up -d PORT=5004
SAS_PATH=/path/to/sas/executable.exe
DRIVE_PATH=./tmp
``` ```
It uses specified docker compose file i.e. `docker-compose.prod.yml` present at root. Setting these prompts variables will avoid the need for prompts.
It will build following images if running first time:
- `sasjs_server_prod` - image for sasjs server app containing api and web component's build served at route `/` 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:
- `mongodb` - image for mongo database
- `mongo-seed-users` - will be populating user data specified in _./mongo-seed/users/user.json_
- `mongo-seed-clients` - will be populating client data specified in _./mongo-seed/clients/client.json_
### Using node: ```bash
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
export PORT=5001
export DRIVE_PATH=./tmp
#### Development (running api and web seperately): forever start -c "./api-linux" ./
##### API
Navigate to `./api`
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
Command to install and run api server.
```
npm install
npm start
``` ```
##### Web To get the log files:
```bash
Navigate to `./web` forever list
There is `.env.example` file present at `./web` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files # grap log file link
Command to install and run api server. tail -f LOGFILE
```
npm install
npm start
``` ```
#### Development (running only api server and have web build served): To stop:
##### API server also serving Web build files
There is `.env.example` file present at `./api` directory. Remember to provide enviornment variables else default values will be used mentioned in `.env.example` files
Command to install and run api server.
``` ```
cd ./web && npm i && npm build && cd ../ forever stop <pid>
cd ./api && npm i && npm start
``` ```
#### Production
##### API & WEB
```
npm run server
```
This will install/build `web` and install `api`, then start prod server.
## Executables
Command to generate executables
```
cd ./web && npm i && npm build && cd ../
cd ./api && npm i && npm run exe
```
This will install/build web app and install/create executables of sasjs server at root `./executables`

89
SASjsServer.drawio Normal file
View File

@@ -0,0 +1,89 @@
<mxfile host="65bd71144e">
<diagram id="HJy_QFGaI9JSrArARLup" name="Page-1">
<mxGraphModel dx="1908" dy="2140" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="4" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
<mxGeometry x="-360" y="-120" width="40" height="80" as="geometry"/>
</mxCell>
<mxCell id="7" value="SASjs Server" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;fontSize=30;" vertex="1" parent="1">
<mxGeometry x="30" y="-150" width="360" height="850" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="28">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-340" y="23" as="sourcePoint"/>
<mxPoint x="115" y="22.586363636363558" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="11" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/authorize&lt;br&gt;(username,password,clientId)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="8">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="14" value="" style="edgeStyle=none;html=1;exitX=-0.002;exitY=0.874;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="28">
<mxGeometry relative="1" as="geometry">
<mxPoint x="110" y="80" as="sourcePoint"/>
<mxPoint x="-340" y="80" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="16" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`code`&lt;/span&gt;&lt;/font&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="14">
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="21" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
<mxGeometry x="-360" y="545" width="40" height="80" as="geometry"/>
</mxCell>
<mxCell id="22" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="30">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-340" y="165" as="sourcePoint"/>
<mxPoint x="115" y="165" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="23" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/token&lt;/span&gt;&lt;/div&gt;&lt;span style=&quot;color: #a31515&quot;&gt;(clientId,code)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="22">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="24" value="" style="edgeStyle=none;html=1;exitX=0.009;exitY=0.905;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="30">
<mxGeometry relative="1" as="geometry">
<mxPoint x="210" y="222.5" as="sourcePoint"/>
<mxPoint x="-340" y="223" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="25" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;accessToken&lt;/span&gt;&lt;span style=&quot;font-size: 12px ; color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace&quot;&gt;` &amp;amp; `&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;refreshToken&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;`&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="24">
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="26" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;" edge="1" parent="1" source="21" target="4">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="40" y="240" as="sourcePoint"/>
<mxPoint x="90" y="190" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="28" value="&lt;span&gt;Validates&lt;/span&gt;&lt;br&gt;&lt;span&gt;username/password/clientId&lt;/span&gt;&lt;br&gt;&lt;span&gt;and issue short&lt;/span&gt;&lt;br&gt;&lt;span&gt;Authorization code&lt;/span&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" width="190" height="90" as="geometry"/>
</mxCell>
<mxCell id="30" value="Validates&lt;br&gt;clientId &amp;amp; authorization code&lt;br&gt;and issue&lt;br&gt;Access Token &amp;amp; Refresh Token" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" y="140" width="190" height="90" as="geometry"/>
</mxCell>
<mxCell id="32" value="Protected APIs&lt;br&gt;Authenticate requests &lt;br&gt;with provided Bearer Token" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
<mxGeometry x="50" y="280" width="320" height="400" as="geometry"/>
</mxCell>
<mxCell id="33" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.373;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="32">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-340" y="432.5" as="sourcePoint"/>
<mxPoint x="-10" y="430" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="34" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;font color=&quot;#a31515&quot;&gt;Request with Access Token&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="33">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

1161
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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": "4.8.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",
@@ -88,4 +88,4 @@
"configuration": { "configuration": {
"sasPath": "/opt/sas/sas9/SASHome/SASFoundation/9.4/sas" "sasPath": "/opt/sas/sas9/SASHome/SASFoundation/9.4/sas"
} }
} }

View File

@@ -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:

View File

@@ -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' }))

View File

@@ -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')
@@ -63,7 +64,15 @@ export class ExecutionController {
%let _sasjs_apipath=/SASjsApi/stp/execute; %let _sasjs_apipath=/SASjsApi/stp/execute;
%let _metaperson=&_sasjs_displayname; %let _metaperson=&_sasjs_displayname;
%let _metauser=&_sasjs_username; %let _metauser=&_sasjs_username;
%let sasjsprocessmode=Stored Program;` %let sasjsprocessmode=Stored Program;
%global SYSPROCESSMODE SYSTCPIPHOSTNAME SYSHOSTINFOLONG;
%macro _sasjs_server_init();
%if "&SYSPROCESSMODE"="" %then %let SYSPROCESSMODE=&sasjsprocessmode;
%if "&SYSTCPIPHOSTNAME"="" %then %let SYSTCPIPHOSTNAME=&_sasjs_apiserverurl;
%mend;
%_sasjs_server_init()
`
program = ` program = `
/* runtime vars */ /* runtime vars */
@@ -100,14 +109,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 +122,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 {

View File

@@ -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,7 +36,7 @@ export class SessionController {
return session return session
} }
private async createSession() { private async createSession(): Promise<Session> {
const sessionId = generateUniqueFileName(generateTimestamp()) const sessionId = generateUniqueFileName(generateTimestamp())
const sessionFolder = path.join(getTmpSessionsFolderPath(), sessionId) const sessionFolder = path.join(getTmpSessionsFolderPath(), sessionId)
@@ -47,6 +51,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 +110,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 +127,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) {
@@ -153,6 +157,7 @@ const autoExecContent = `
data _null_; data _null_;
/* remove the dummy SYSIN */ /* remove the dummy SYSIN */
length fname $8; length fname $8;
call missing(fname);
rc=filename(fname,getoption('SYSIN') ); rc=filename(fname,getoption('SYSIN') );
if rc = 0 and fexist(fname) then rc=fdelete(fname); if rc = 0 and fexist(fname) then rc=fdelete(fname);
rc=filename(fname); rc=filename(fname);

View File

@@ -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
} }

View File

@@ -7,7 +7,7 @@ import { getRealPath } from '@sasjs/utils'
export const connectDB = async () => { export const connectDB = async () => {
// NOTE: when exporting app.js as agent for supertest // NOTE: when exporting app.js as agent for supertest
// we should exlcude connecting to the real database // we should exclude connecting to the real database
if (process.env.NODE_ENV === 'test') { if (process.env.NODE_ENV === 'test') {
process.driveLoc = path.join(process.cwd(), 'tmp') process.driveLoc = path.join(process.cwd(), 'tmp')
return return

View File

@@ -14,14 +14,14 @@ services:
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET} REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
AUTH_CODE_SECRET: ${AUTH_CODE_SECRET} AUTH_CODE_SECRET: ${AUTH_CODE_SECRET}
DB_CONNECT: mongodb://mongodb:27017/sasjs DB_CONNECT: mongodb://mongodb:27017/sasjs
SAS_PATH: /usr/server/sasexe SAS_PATH: /usr/server/sasexe/${SAS_EXEC_NAME}
expose: expose:
- ${PORT_API} - ${PORT_API}
ports: ports:
- ${PORT_API}:${PORT_API} - ${PORT_API}:${PORT_API}
volumes: volumes:
- type: bind - type: bind
source: ${SAS_EXEC} source: ${SAS_EXEC_PATH}
target: /usr/server/sasexe target: /usr/server/sasexe
read_only: true read_only: true
links: links:

16
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "server", "name": "server",
"version": "0.0.15", "version": "0.0.25",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "server", "name": "server",
"version": "0.0.15", "version": "0.0.25",
"devDependencies": { "devDependencies": {
"prettier": "^2.3.1", "prettier": "^2.3.1",
"standard-version": "^9.3.2" "standard-version": "^9.3.2"
@@ -865,9 +865,9 @@
} }
}, },
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.8", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"dev": true "dev": true
}, },
"node_modules/handlebars": { "node_modules/handlebars": {
@@ -2787,9 +2787,9 @@
} }
}, },
"graceful-fs": { "graceful-fs": {
"version": "4.2.8", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"dev": true "dev": true
}, },
"handlebars": { "handlebars": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "server", "name": "server",
"version": "0.0.15", "version": "0.0.25",
"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": {