Add a webservice API with polling
This commit is contained in:
		
							parent
							
								
									54ed7308a8
								
							
						
					
					
						commit
						4c34db1af9
					
				| @ -12,15 +12,19 @@ get_width(){ | ||||
| 
 | ||||
| 
 | ||||
| annotate_header(){ | ||||
|   echo annotate $1 | ||||
|   echo annotate $1 $2 $3 | ||||
|   filename=$1 | ||||
|   shift; | ||||
|   domain=$1; | ||||
|   shift; | ||||
|   count=$1; | ||||
|   shift; | ||||
|   d=$(date "+%Y-%m-%d__%H_%M_%S") | ||||
|   #filename="2022-03-10__19_33_55__set-cookie.png" | ||||
|   cropped_filename="${filename}__cropped.png" | ||||
|   overlay_filename="${cropped_filename}__overlay.png" | ||||
|   hardoverlay_filename="${cropped_filename}__hardoverlay.png" | ||||
|   annotated_filename="${cropped_filename}__annotated.png" | ||||
|   annotated_filename="$(dirname "$filename")/${domain}__${count}.final.png" # the name is crucial, because the web app part filters files based on the name | ||||
| 
 | ||||
|   # crop  | ||||
|   left=2056 | ||||
| @ -78,10 +82,10 @@ annotate_header(){ | ||||
|     shift | ||||
|     shift | ||||
|   done | ||||
|   convert "$filename" "$overlay_filename" -compose Darken -composite "$annotated_filename.step.png" | ||||
|   convert "$annotated_filename.step.png" "$hardoverlay_filename" -compose src-over -composite "$annotated_filename" | ||||
|   convert "$filename" "$overlay_filename" -compose Darken -composite "${annotated_filename}.step.png" | ||||
|   convert "${annotated_filename}.step.png" "$hardoverlay_filename" -compose src-over -composite "$annotated_filename" | ||||
|   rm "$overlay_filename" "$annotated_filename.step.png" "$hardoverlay_filename" "$cropped_filename" "$filename" | ||||
|   echo "SCREENSHOT: <img width=\"720\" height=\"405\" src=\"$BASE_URL/$(echo "$annotated_filename" | sed 's|/opt/||')\"/>" | ||||
|   echo "SCREENSHOT: <img width=\"720\" height=\"405\" src=\"${BASE_URL}/$(echo "$annotated_filename" | sed 's|/opt/||')\"/>" | ||||
| } | ||||
| 
 | ||||
| #annotate_header "set-cookie" "identyfikator internetowy z cookie" "Cookie" "identyfikator internetowy z cookie" | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,4 +1,4 @@ | ||||
| #!/bin/bash  | ||||
| #!/bin/bash | ||||
| 
 | ||||
| INPUT="$1" | ||||
| ID=$2 | ||||
| @ -14,11 +14,11 @@ source ./ephemeral-x.sh | ||||
| source ./annotate_header.sh | ||||
| source ./utils.sh | ||||
| 
 | ||||
| (while true; do | ||||
|    grab_screen_to_public $ID | ||||
|    sleep 1 | ||||
|  done) & | ||||
| refresher_pid=$!; | ||||
| # (while true; do | ||||
| #    grab_screen_to_public $ID | ||||
| #    sleep 1 | ||||
| #  done) & | ||||
| # refresher_pid=$!; | ||||
| 
 | ||||
| start_firefox | ||||
| grab start_firefox | ||||
| @ -53,7 +53,7 @@ while IFS= read -r DOMAIN; do | ||||
|     do | ||||
|       filename="/opt/static/$ID/${index}.png" | ||||
|       scrot "$filename" | ||||
|       annotate_header "$filename" \ | ||||
|       annotate_header "$filename" "$DOMAIN" "$count" \ | ||||
|         "set-cookie" "identyfikator internetowy z cookie" \ | ||||
|         "Cookie" "identyfikator internetowy z cookie" \ | ||||
|         "Referer" "Część mojej historii przeglądania" & | ||||
| @ -67,7 +67,7 @@ while IFS= read -r DOMAIN; do | ||||
|     done | ||||
| done <<< "$DOMAINS" | ||||
| 
 | ||||
| kill $refresher_pid; | ||||
| # kill $refresher_pid; | ||||
| 
 | ||||
| echo "starting wait..." | ||||
| 
 | ||||
|  | ||||
| @ -28,7 +28,7 @@ click (){ | ||||
| 
 | ||||
| grab_no=0 | ||||
| 
 | ||||
| grab (){ | ||||
| grab(){ | ||||
|   NOTE="$grab_no $@" | ||||
|   #echo $@ | ||||
|   ((grab_no++)) | ||||
|  | ||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @ -23,3 +23,13 @@ BASE_URL=http://localhost:3000 docker run -i -v $PWD/static:/opt/static  headles | ||||
| ``` | ||||
| BASE_URL=http://localhost:3000 node . | ||||
| ``` | ||||
| 
 | ||||
| ## Testing the API | ||||
| 
 | ||||
| with httpie: | ||||
| 
 | ||||
| ``` | ||||
| http POST localhost:3000/api/requests url==pearson.com 'domains[]==youtube.com' 'domains[]==facebook.com' | ||||
| ``` | ||||
| 
 | ||||
| It returns a 303 response that redirects to a URL you can poll to see the status of the screenshot request. | ||||
|  | ||||
							
								
								
									
										10
									
								
								docker-args.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docker-args.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| const DOCKER_ARGS = [ | ||||
|   "run", | ||||
|   "-i", | ||||
|   "-v", | ||||
|   `${process.cwd()}/static:/opt/static`, | ||||
|   "headless-fox", | ||||
|   "./script3.sh", | ||||
| ]; | ||||
| 
 | ||||
| module.exports = DOCKER_ARGS; | ||||
							
								
								
									
										43
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								index.js
									
									
									
									
									
								
							| @ -1,4 +1,3 @@ | ||||
| const { v4: uuid } = require("uuid"); | ||||
| var serve = require("koa-static"); | ||||
| const Koa = require("koa"); | ||||
| const Router = require("@koa/router"); | ||||
| @ -6,6 +5,9 @@ const mount = require("koa-mount"); | ||||
| const qs = require("qs"); | ||||
| const { Readable } = require("stream"); | ||||
| const { spawn } = require("child_process"); | ||||
| const { requests } = require("./memory"); | ||||
| const ScreenshotRequest = require("./request"); | ||||
| const DOCKER_ARGS = require("./docker-args"); | ||||
| 
 | ||||
| const router = new Router(); | ||||
| 
 | ||||
| @ -65,13 +67,7 @@ router.get("/", async (ctx) => { | ||||
|   const starter = spawn( | ||||
|     "docker", | ||||
|     [ | ||||
|       "run", | ||||
|       "-i", | ||||
|       "-d", | ||||
|       "-v", | ||||
|       `${process.cwd()}/static:/opt/static`, | ||||
|       "headless-fox", | ||||
|       "./script3.sh", | ||||
|       ...DOCKER_ARGS, | ||||
|       `{"url": "${params.url}", "third_party_domains": ["hotjar.com", "cookielaw.org", "facebook.com", "gemius.pl"]}`, | ||||
|       id, | ||||
|     ], | ||||
| @ -87,5 +83,36 @@ router.get("/", async (ctx) => { | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| router.post("/api/requests", async (ctx) => { | ||||
|   const params = qs.parse(ctx.querystring); | ||||
|   if (!params.url) { | ||||
|     ctx.body = "Specify url"; | ||||
|     ctx.status = 422; | ||||
|     return; | ||||
|   } | ||||
|   if (!params.domains) { | ||||
|     ctx.body = "Specify domains"; | ||||
|     ctx.status = 422; | ||||
|     return; | ||||
|   } | ||||
|   if (!Array.isArray(params.domains)) { | ||||
|     ctx.body = "'domains' should be an array of strings"; | ||||
|     ctx.status = 422; | ||||
|     return; | ||||
|   } | ||||
|   const request = new ScreenshotRequest(params.url, params.domains); | ||||
|   ctx.status = 303; | ||||
|   ctx.redirect(`/api/requests/${request.id}`); | ||||
| }); | ||||
| 
 | ||||
| router.get("/api/requests/:id", async (ctx) => { | ||||
|   const request = requests[ctx.params.id]; | ||||
|   if (!request) { | ||||
|     ctx.status = 404; | ||||
|     return; | ||||
|   } | ||||
|   ctx.body = await request.getJSON(); | ||||
| }); | ||||
| 
 | ||||
| app.use(router.routes()).use(router.allowedMethods()); | ||||
| app.listen(3000); | ||||
|  | ||||
							
								
								
									
										3
									
								
								memory.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								memory.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| const queue = require("queue"); | ||||
| const q = queue({ concurrency: 1, autostart: true, results: [] }); | ||||
| b; | ||||
							
								
								
									
										17
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										17
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -15,6 +15,7 @@ | ||||
|         "koa-mount": "^4.0.0", | ||||
|         "koa-static": "^5.0.0", | ||||
|         "qs": "^6.10.3", | ||||
|         "queue": "^6.0.2", | ||||
|         "uuid": "^8.3.2" | ||||
|       } | ||||
|     }, | ||||
| @ -571,6 +572,14 @@ | ||||
|       "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", | ||||
|       "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" | ||||
|     }, | ||||
|     "node_modules/queue": { | ||||
|       "version": "6.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", | ||||
|       "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", | ||||
|       "dependencies": { | ||||
|         "inherits": "~2.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/readable-stream": { | ||||
|       "version": "1.1.14", | ||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", | ||||
| @ -1167,6 +1176,14 @@ | ||||
|       "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", | ||||
|       "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" | ||||
|     }, | ||||
|     "queue": { | ||||
|       "version": "6.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", | ||||
|       "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", | ||||
|       "requires": { | ||||
|         "inherits": "~2.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "readable-stream": { | ||||
|       "version": "1.1.14", | ||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", | ||||
|  | ||||
| @ -19,6 +19,7 @@ | ||||
|     "koa-mount": "^4.0.0", | ||||
|     "koa-static": "^5.0.0", | ||||
|     "qs": "^6.10.3", | ||||
|     "queue": "^6.0.2", | ||||
|     "uuid": "^8.3.2" | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										75
									
								
								request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								request.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| const { q, requests } = require("./memory"); | ||||
| const DOCKER_ARGS = require("./docker-args"); | ||||
| const { v4: uuid } = require("uuid"); | ||||
| const { promises: fs } = require("fs"); | ||||
| const { spawn } = require("child_process"); | ||||
| const { resolve } = require("path"); | ||||
| 
 | ||||
| module.exports = class ScreenshotRequest { | ||||
|   constructor(url, domains) { | ||||
|     this.url = url; | ||||
|     this.domains = domains; | ||||
|     this.id = uuid(); | ||||
|     this.status = "waiting"; | ||||
|     this.output = ""; | ||||
|     this.images = []; | ||||
|     q.push(async () => { | ||||
|       return this.exec(); | ||||
|     }); | ||||
|     requests[this.id] = this; | ||||
|   } | ||||
| 
 | ||||
|   async getImages() { | ||||
|     try { | ||||
|       const files = await fs.readdir(resolve(__dirname, "./static/" + this.id)); | ||||
|       return files.filter((file) => file.match(/.final.png$/)); | ||||
|     } catch (e) { | ||||
|       return []; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   async getJSON() { | ||||
|     return { | ||||
|       url: this.url, | ||||
|       domains: this.domains, | ||||
|       id: this.id, | ||||
|       status: this.status, | ||||
|       /* output: this.output, */ | ||||
|       files: await this.getImages(), | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   async exec() { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       this.status = "running"; | ||||
|       this.process = spawn( | ||||
|         "docker", | ||||
|         [ | ||||
|           ...DOCKER_ARGS, | ||||
|           JSON.stringify({ | ||||
|             url: this.url, | ||||
|             third_party_domains: this.domains, | ||||
|           }), | ||||
|           this.id, | ||||
|         ], | ||||
|         { cwd: process.cwd() } | ||||
|       ); | ||||
|       this.process.on("close", (exitCode) => { | ||||
|         this.status = "finished"; | ||||
|         if (exitCode === 0) { | ||||
|           resolve(); | ||||
|         } else { | ||||
|           reject(); | ||||
|         } | ||||
|       }); | ||||
|       this.process.stdout.on("data", (d) => { | ||||
|         this.output += d.toString(); | ||||
|         /* console.log("DATA!", d.toString()); */ | ||||
|       }); | ||||
|       this.process.stderr.on("data", (d) => { | ||||
|         this.output += d.toString(); | ||||
|         /* console.log("STDERR!", d.toString()); */ | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user