From 5110db66c96fccf5565a16f416ac29b65ff5d5ac Mon Sep 17 00:00:00 2001 From: zak <8143258+ZakisM@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:59:26 +0000 Subject: [PATCH] feat: use golang for playwright --- .github/workflows/deploy.yml | 2 +- playwright_bridge/.gitignore | 175 ------------------ playwright_bridge/Dockerfile | 26 --- playwright_bridge/README.md | 15 -- playwright_bridge/bun.lockb | Bin 4242 -> 0 bytes playwright_bridge/index.ts | 71 ------- playwright_bridge/package.json | 15 -- playwright_bridge/tsconfig.json | 27 --- playwright_bridge_go/Dockerfile | 13 ++ playwright_bridge_go/go.mod | 27 +++ playwright_bridge_go/go.sum | 62 +++++++ playwright_bridge_go/main.go | 59 ++++++ .../playwright_helper/playwright_helper.go | 80 ++++++++ 13 files changed, 242 insertions(+), 330 deletions(-) delete mode 100644 playwright_bridge/.gitignore delete mode 100644 playwright_bridge/Dockerfile delete mode 100644 playwright_bridge/README.md delete mode 100755 playwright_bridge/bun.lockb delete mode 100644 playwright_bridge/index.ts delete mode 100644 playwright_bridge/package.json delete mode 100644 playwright_bridge/tsconfig.json create mode 100644 playwright_bridge_go/Dockerfile create mode 100644 playwright_bridge_go/go.mod create mode 100644 playwright_bridge_go/go.sum create mode 100644 playwright_bridge_go/main.go create mode 100644 playwright_bridge_go/playwright_helper/playwright_helper.go diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4ff18af..0c9ef87 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -55,7 +55,7 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v5.1.0 with: - context: ./playwright_bridge + context: ./playwright_bridge_go push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/playwright_bridge/.gitignore b/playwright_bridge/.gitignore deleted file mode 100644 index 9b1ee42..0000000 --- a/playwright_bridge/.gitignore +++ /dev/null @@ -1,175 +0,0 @@ -# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - -# Logs - -logs -_.log -npm-debug.log_ -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Caches - -.cache - -# Diagnostic reports (https://nodejs.org/api/report.html) - -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# Runtime data - -pids -_.pid -_.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover - -lib-cov - -# Coverage directory used by tools like istanbul - -coverage -*.lcov - -# nyc test coverage - -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) - -.grunt - -# Bower dependency directory (https://bower.io/) - -bower_components - -# node-waf configuration - -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) - -build/Release - -# Dependency directories - -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) - -web_modules/ - -# TypeScript cache - -*.tsbuildinfo - -# Optional npm cache directory - -.npm - -# Optional eslint cache - -.eslintcache - -# Optional stylelint cache - -.stylelintcache - -# Microbundle cache - -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history - -.node_repl_history - -# Output of 'npm pack' - -*.tgz - -# Yarn Integrity file - -.yarn-integrity - -# dotenv environment variable files - -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) - -.parcel-cache - -# Next.js build output - -.next -out - -# Nuxt.js build / generate output - -.nuxt -dist - -# Gatsby files - -# Comment in the public line in if your project uses Gatsby and not Next.js - -# https://nextjs.org/blog/next-9-1#public-directory-support - -# public - -# vuepress build output - -.vuepress/dist - -# vuepress v2.x temp and cache directory - -.temp - -# Docusaurus cache and generated files - -.docusaurus - -# Serverless directories - -.serverless/ - -# FuseBox cache - -.fusebox/ - -# DynamoDB Local files - -.dynamodb/ - -# TernJS port file - -.tern-port - -# Stores VSCode versions used for testing VSCode extensions - -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store diff --git a/playwright_bridge/Dockerfile b/playwright_bridge/Dockerfile deleted file mode 100644 index 5bf773f..0000000 --- a/playwright_bridge/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM oven/bun:1 as base -WORKDIR /usr/src/app - -FROM base AS install -RUN mkdir -p /temp/dev -COPY package.json bun.lockb /temp/dev/ -RUN cd /temp/dev && bun install --frozen-lockfile - -RUN mkdir -p /temp/prod -COPY package.json bun.lockb /temp/prod/ -RUN cd /temp/prod && bun install --frozen-lockfile --production - -FROM base AS prerelease -COPY --from=install /temp/dev/node_modules node_modules -COPY . . - -ENV NODE_ENV=production - -FROM mcr.microsoft.com/playwright:v1.41.1-jammy -COPY --from=install /temp/prod/node_modules node_modules -COPY --from=prerelease /usr/src/app/index.ts . -COPY --from=prerelease /usr/src/app/package.json . -RUN npm install -g bun - -ENTRYPOINT [ "bun", "run", "index.ts" ] - diff --git a/playwright_bridge/README.md b/playwright_bridge/README.md deleted file mode 100644 index 109fe59..0000000 --- a/playwright_bridge/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# playwright_bridge - -To install dependencies: - -```bash -bun install -``` - -To run: - -```bash -bun run index.ts -``` - -This project was created using `bun init` in bun v1.0.29. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/playwright_bridge/bun.lockb b/playwright_bridge/bun.lockb deleted file mode 100755 index 25d7891090202fed089911c0f222c593b941a66e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4242 zcmeHKX;2hL6rRNu*9{S+uryvQoK#pM*y589@+L(JQKFwgem* zxb=7pol<|#?6ncak9W9a7hDhpeobd?F&hjfWm0`%>w)4!I~+T`a3XZvNXXw5mc zZT+x~jY-#2+&k)vT&kP)O-Pvh`bH}7yt#d`hkV_GxCZsbB&)k)GcW9n*|)NiPLVC! zJn^X8w1GO;vU;ywi2k_*MGc7znj83s`0SzKdFb{k*e(vNRDeh0e$eoIuV53qBhY{I zIo3A^$6W#6A9&FEsP#p#pYDKn=GRBK0eu034aTFuxtQQb{Y(5Mz&imRWhB}|w*>5k z3$Nb~I@1Af4YrVP1k!yGjDH(CvjLCR9sv#MzKReGQA1qjJm^UpwrGeevV${1pfTDf z(#U5lFP5*}vK=k(f<-_Wc}=N>C2#z&O5Z$uo8F?tUT~|rE#JN7Q8rOl=^hrJ?EmLG zr91SQZ{@d?&&*3q{X;lRlIFEOxy(sSJ7v_?$L$$Yavyv|yf~KFWnq~^^6W7RK~2>$ z8|^aPzM;cJ)6Lc?$E}-r=hKhJw{H1oAT6hoS_)`p!Zm@B_slpY^HO{pH_&JX9AS<9jD_plxE|+_Nk0HJ{mVt^DD+W#jF->ctJe*Cc&@BRrqErtI+WP8}z*Y%gf`%AB@Xzhu8{Qr=mg43X7_58~ZU z#0iJr%zI$Mi(-vM*wj+-%c9i3TaJ&jty*7s+afo*xuIcIPMi6>Tg1V4z0)(s&MCBP zs?)Qwi)-fW*;RWq!hdtIkG=W6z#VNzE_uK`(HUQK4zUO)E=YE{qvzbk2fS9NeP-jG zVC^01c(2r@d}htVNbca&>^$4r1)t2nI9^tqxbyv({>x=aYYwN{KB_747#dO^n}vyb zXms8uKtu1(APr5fWP2F!Lu7~FtJn_b71mEizWiC!d*J1J^S=juk3cs6sy)tYu`A02 zk+hcO0yG*D7nOy!NL9}-m1+9(FRUQA21^;pr zyGA%FX8`ai6ex$#{fzD=l<(;7L-z?f`-n=#^91*S595)>y!ic$_%JW>b0^Q24+Sa` zv8#`Aif@DpwmYTMS4H>j;<^{ttAho8&ZL}_6U0cw04E(+up%=}07tPLLG;9k5XO;o z?7AIrRct2kQ;<#yQrUSQ;QH81!2dzuN*q_vLV*&vddb!#^t0nN-N1fN?-U0>L#suEhc4Oe&|4P6Y9)(P9>_yXO>3g+)>f zIX9Z47;S)N5y#M4^$dxkE7+>eU~_Dcf$C(d^?qjiHf!`Dgyt--XSz0yUR}tsEX4qu zZ^3FII=SH;sFD-o^2oobtvZ_$k4%R zii-)S*dT@u=VlqYGWh)JG79CmaCW*(#!zaS<(L>!8y>cjC3TEi)@3Af(H@WU^<9?=0;4-fW~wPVT1$ZjL3}n`rrHg2XwGV)&Kwi diff --git a/playwright_bridge/index.ts b/playwright_bridge/index.ts deleted file mode 100644 index 1faf2b6..0000000 --- a/playwright_bridge/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -import {webkit, type Browser} from 'playwright'; - -function invariant(condition: any, message: string): asserts condition { - if (condition) return; - - throw new Error(message); -} - -let browser: Browser; - -const getPageSource = async (url: string, timeout: number) => { - if (!browser) { - try { - browser = await webkit.launch({headless: true}); - } catch (error) { - console.error(error); - process.exit(1); - } - } - - let res: string | undefined; - - try { - const page = await browser.newPage(); - await page.route( - '**/*.{css,png,jpg,jpeg,mp4,mp3,ttf,ttf2,woff,woff2,webp,svg,xml}', - (route) => route.abort(), - ); - await page.goto(url, {timeout: timeout * 1000}); - - res = await page.content(); - - await page.close(); - } catch (error) { - console.error(`Failed to get ${URL} due to: ${error}`); - } - - invariant( - res !== undefined, - `Response was undefined when trying to to read page source for: ${URL}`, - ); - - return res; -}; - -Bun.serve({ - development: false, - async fetch(req: Request) { - const {searchParams} = new URL(req.url); - - const url = searchParams.get('url'); - invariant(url !== null, 'url was null'); - - const timeout = Number(searchParams.get('timeout')); - invariant( - timeout !== null && !Number.isNaN(timeout), - 'timeout was null | NaN', - ); - - try { - const source = await getPageSource(url, Number(timeout)); - - return new Response(source); - } catch (error) { - throw new Error( - `Failed to call 'getPageSource' for '${URL}' due to: ${error}`, - ); - } - }, - port: 8050, -}); diff --git a/playwright_bridge/package.json b/playwright_bridge/package.json deleted file mode 100644 index 7ac5840..0000000 --- a/playwright_bridge/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "playwright_bridge", - "module": "index.ts", - "type": "module", - "devDependencies": { - "@types/bun": "latest", - "typescript": "^5.3.3" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "playwright": "^1.41.2" - } -} \ No newline at end of file diff --git a/playwright_bridge/tsconfig.json b/playwright_bridge/tsconfig.json deleted file mode 100644 index b6e46be..0000000 --- a/playwright_bridge/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - // Enable latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - - // Bundler mode - "moduleResolution": "node", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false - } -} diff --git a/playwright_bridge_go/Dockerfile b/playwright_bridge_go/Dockerfile new file mode 100644 index 0000000..bb7669d --- /dev/null +++ b/playwright_bridge_go/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:latest as builder +WORKDIR /app +COPY go.mod go.sum . +RUN go mod download +RUN go run github.com/playwright-community/playwright-go/cmd/playwright@latest install webkit +COPY *.go . +COPY playwright_helper ./playwright_helper +RUN CGO_ENABLED=0 GOOS=linux go build -o /app/playwright-bridge-go + +FROM mcr.microsoft.com/playwright:v1.41.1-jammy +COPY --from=builder /app/playwright-bridge-go ./app/ +COPY --from=builder ../root/.cache/ms-playwright-go ../root/.cache/ms-playwright-go +ENTRYPOINT ["/app/playwright-bridge-go"] diff --git a/playwright_bridge_go/go.mod b/playwright_bridge_go/go.mod new file mode 100644 index 0000000..0aec9ad --- /dev/null +++ b/playwright_bridge_go/go.mod @@ -0,0 +1,27 @@ +module main + +go 1.22.0 + +require ( + github.com/labstack/echo/v4 v4.11.4 + github.com/playwright-community/playwright-go v0.4101.1 +) + +require ( + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect +) diff --git a/playwright_bridge_go/go.sum b/playwright_bridge_go/go.sum new file mode 100644 index 0000000..f21eca1 --- /dev/null +++ b/playwright_bridge_go/go.sum @@ -0,0 +1,62 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/playwright-community/playwright-go v0.4101.1 h1:MrValJr0Cx0GLnfrF7/bzL6odtr3WNj5f2YYO+bntHs= +github.com/playwright-community/playwright-go v0.4101.1/go.mod h1:IVr5cwkhRObh/7jvs97rzi9L5luk0c/+iPz5TmXRTtg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= +golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/playwright_bridge_go/main.go b/playwright_bridge_go/main.go new file mode 100644 index 0000000..f59f87d --- /dev/null +++ b/playwright_bridge_go/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "log" + "log/slog" + "net/http" + "strconv" + + "main/playwright_helper" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" +) + +const ( + playwrightContextKey string = "playwright" +) + +func contentHandler(c echo.Context) error { + url := c.QueryParam("url") + + timeoutStr := c.QueryParam("timeout") + timeout, err := strconv.Atoi(timeoutStr) + if err != nil { + return err + } + + slog.Info(fmt.Sprintf("%s, %v", url, timeout)) + + pwh := c.Get(playwrightContextKey).(*playwright_helper.PlaywrightHelper) + + content, err := pwh.GetPageContent(url, timeout) + if err != nil { + return err + } + + return c.String(http.StatusOK, *content) +} + +func main() { + pwh, err := playwright_helper.New() + defer pwh.Close() + if err != nil { + log.Fatalf("%v", err) + } + + e := echo.New() + e.GET("/", contentHandler) + e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + c.Set(playwrightContextKey, pwh) + return next(c) + } + }) + e.Use(middleware.Logger()) + e.Logger.Fatal(e.Start("0.0.0.0:8050")) + +} diff --git a/playwright_bridge_go/playwright_helper/playwright_helper.go b/playwright_bridge_go/playwright_helper/playwright_helper.go new file mode 100644 index 0000000..81ab69f --- /dev/null +++ b/playwright_bridge_go/playwright_helper/playwright_helper.go @@ -0,0 +1,80 @@ +package playwright_helper + +import ( + "fmt" + "log" + "sync" + + "github.com/playwright-community/playwright-go" +) + +type PlaywrightHelper struct { + pw *playwright.Playwright + mutex sync.Mutex + browser playwright.Browser +} + +func New() (*PlaywrightHelper, error) { + pw, err := playwright.Run() + if err != nil { + return nil, fmt.Errorf("could not start playwright: %v", err) + } + + browser, err := pw.WebKit.Launch(playwright.BrowserTypeLaunchOptions{ + Headless: playwright.Bool(true), + }) + if err != nil { + return nil, fmt.Errorf("could not launch browser: %v", err) + } + + res := PlaywrightHelper{ + pw: pw, + browser: browser, + } + + return &res, nil +} + +func (pwh *PlaywrightHelper) GetPageContent(url string, timeout int) (*string, error) { + pwh.mutex.Lock() + defer pwh.mutex.Unlock() + + page, err := (pwh.browser).NewPage() + if err != nil { + return nil, err + } + + page.Route("**/*.{css,png,jpg,jpeg,mp4,mp3,ttf,ttf2,woff,woff2,webp,svg,xml}", func(route playwright.Route) { + route.Abort() + }) + + if _, err = page.Goto(url, playwright.PageGotoOptions{ + Timeout: playwright.Float(float64(timeout * 1000)), + }); err != nil { + return nil, err + } + + content, err := page.Content() + if err != nil { + log.Fatalf("could not read content: %v", err) + } + + err = page.Close() + if err != nil { + log.Fatalf("failed to close page: %v", err) + } + + return &content, nil +} + +func (pwh *PlaywrightHelper) Close() { + pwh.mutex.Lock() + defer pwh.mutex.Unlock() + + if err := pwh.browser.Close(); err != nil { + log.Fatalf("could not close browser: %v", err) + } + if err := pwh.pw.Stop(); err != nil { + log.Fatalf("could not stop Playwright: %v", err) + } +}