@vpalmisano/webrtcperf 4.5.2 → 4.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.min.js +1 -1
- package/build/src/app.js +8 -3
- package/build/src/app.js.map +1 -1
- package/build/src/config.d.ts +1 -0
- package/build/src/config.js +9 -1
- package/build/src/config.js.map +1 -1
- package/build/src/docker.js +18 -1
- package/build/src/docker.js.map +1 -1
- package/build/src/plot.js +13 -4
- package/build/src/plot.js.map +1 -1
- package/build/src/rtcstats.d.ts +4 -0
- package/build/src/rtcstats.js +6 -3
- package/build/src/rtcstats.js.map +1 -1
- package/build/src/scenarios.d.ts +2 -1
- package/build/src/scenarios.js +1 -1
- package/build/src/scenarios.js.map +1 -1
- package/build/src/server.js +5 -5
- package/build/src/server.js.map +1 -1
- package/build/src/session.d.ts +3 -1
- package/build/src/session.js +27 -2
- package/build/src/session.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
- package/src/app.ts +7 -3
- package/src/config.ts +9 -1
- package/src/docker.ts +20 -1
- package/src/plot.ts +12 -4
- package/src/rtcstats.ts +6 -3
- package/src/scenarios.ts +1 -1
- package/src/server.ts +5 -5
- package/src/session.ts +29 -1
package/build/src/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAAqC;AACrC,mCAAwC;AACxC,mDAAuC;AACvC,4CAAmB;AACnB,+BAAyD;AACzD,iCAA4E;AAC5E,4CAAmB;AACnB,gDAAuB;AACvB,oDAAwB;AACxB,2BAAoC;AACpC,gDAAuB;AACvB,4DAA6B;AAE7B,qCAA6C;AAC7C,uCAAkD;AAElD,mCAAoE;AACpE,qDAA+D;AAC/D,mCAAqD;AAErD,MAAM,GAAG,GAAG,IAAA,cAAM,EAAC,mBAAmB,CAAC,CAAA;AAEvC;;;;GAIG;AACH,MAAa,MAAM;IACjB,iCAAiC;IACxB,UAAU,CAAQ;IAC3B,6BAA6B;IACpB,YAAY,CAAQ;IAC7B,wCAAwC;IAC/B,cAAc,CAAS;IAChC,iFAAiF;IACjF,UAAU,CAAQ;IAClB,gFAAgF;IAChF,WAAW,CAAQ;IACnB,mEAAmE;IACnE,cAAc,CAAQ;IACtB,sCAAsC;IACtC,KAAK,CAAO;IAEJ,GAAG,CAAiB;IACpB,MAAM,GAAoC,IAAI,CAAA;IAC9C,GAAG,GAA2B,IAAI,CAAA;IAE1C;;;;;;;;;;;OAWG;IACH,YACE,EACE,UAAU,GAAG,IAAI,EACjB,YAAY,GAAG,QAAQ,EACvB,cAAc,GAAG,KAAK,EACtB,UAAU,GAAG,EAAE,EACf,WAAW,GAAG,EAAE,EAChB,cAAc,GAAG,EAAE,GACpB,GAAG,EAAE,EACN,KAAY;QAEZ,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA;QAChC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;QAC9B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,EAAE;QACF,IAAI,CAAC,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAA;QACpB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAA,qBAAW,GAAE,CAAC,CAAA;QAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CACV,IAAA,cAAI,EAAC;YACH,KAAK,EAAE,MAAM;SACd,CAAC,CACH,CAAA;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;YACvF,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;gBACzC,OAAO,IAAI,EAAE,CAAA;YACf,CAAC;YACD,MAAM,WAAW,GAAG,IAAA,oBAAI,EAAC,GAAG,CAAC,CAAA;YAC7B,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,IAAI,WAAW,CAAC,IAAI,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC3F,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,+BAA+B,CAAC,CAAA;gBAClE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBACpC,OAAM;YACR,CAAC;YACD,IAAI,EAAE,CAAA;QACR,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YAC9B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACd,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAChD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACnE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACrE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACnE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACpD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,uBAAuB,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACpE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC7D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9E,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACzD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,GAAG,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;YACjD,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBAClE,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,UAAU,WAAW,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;YAC7D,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YACrD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACtD,CAAC;QACD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,CAAC,yBAAyB,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA;YACzD,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;gBACtE,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,cAAc,WAAW,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;YACjE,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACxD,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAU,EAAE,GAAoB,EAAE,GAAqB,EAAE,IAA0B,EAAE,EAAE;YACnG,GAAG,CAAC,KAAK,CAAC,gBAAgB,GAAG,CAAC,IAAI,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;YACvD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;YAClB,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH;;;;;;;;;;QAUI;IAEJ;;;;OAIG;IACK,KAAK,CAAC,QAAQ,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC5F,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QACvB,MAAM,KAAK,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACnD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAC3B,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,YAAY,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC1F,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QACvC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAA;QAC7C,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACpC,CAAC;IAED;;;;OAIG;IACK,oBAAoB,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAClG,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QAChD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAA;QACrD,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC5C,CAAC;IAED;;;;;OAKG;IACK,iBAAiB,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC/F,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAA;QACjC,8DAA8D;QAC9D,MAAM,KAAK,GAAwB,EAAE,CAAA;QACrC,IAAI,CAAC;YACH,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;gBACpE,8DAA8D;gBAC9D,KAAK,CAAC,GAAG,CAAC,GAAI,IAAY,CAAC,IAAI,CAAA;YACjC,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,aAAa,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QACjG,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAChD,MAAM,MAAM,GAAG,QAAQ,CAAE,GAAG,CAAC,KAAK,CAAC,IAAe,IAAI,GAAG,CAAC,CAAA;QAC1D,MAAM,MAAM,GAAI,GAAG,CAAC,KAAK,CAAC,MAAiB,IAAI,MAAM,CAAA;QACrD,GAAG,CAAC,KAAK,CAAC,mBAAmB,SAAS,SAAS,MAAM,WAAW,MAAM,EAAE,CAAC,CAAA;QACzE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAClD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,GAAG,CAAC,CAAA;YACtD,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YAC7D,GAAG,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,iBAAiB,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC/F,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAA;QACjC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAA;QACtC,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;YACvD,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,uBAAuB;aACjC,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,UAAU,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC9F,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,GAAG,CAAC,IAAc,CAAA;YACjC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YAC7D,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;YAC1C,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,iBAAiB;gBAC1B,IAAI,EAAE,EAAE,EAAE,EAAE;aACb,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,WAAW,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC/F,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACpC,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,IAAc,CAAA;YACvD,MAAM,WAAW,GAAG,EAAE,CAAA;YACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAA;gBACtD,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;gBAC1C,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACtB,CAAC;YACD,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,GAAG,QAAQ,mBAAmB;gBACvC,IAAI,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE;aAC3B,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,aAAa,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QACjG,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACtC,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAA;YACvB,MAAM,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;YAC/B,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,iBAAiB;gBAC1B,IAAI,EAAE,EAAE,EAAE,EAAE;aACb,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,cAAc,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAClG,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,CAAA;YACxB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;gBACrB,MAAM,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;YACjC,CAAC;YACD,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,mBAAmB;gBACzC,IAAI,EAAE,EAAE,GAAG,EAAE;aACd,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,UAAU,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QACxF,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAA;QAC/C,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAChD,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;IAC9C,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,YAAY,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAChG,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAA,yBAAiB,GAAE,CAAA;YACzC,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC1C,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;YAChD,CAAC;YACD,GAAG,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAA;QACX,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,aAAa,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC3F,GAAG,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QACjD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAA;QAC1D,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAC3C,CAAC;IAED;;;;;OAKG;IACK,YAAY,CAAC,GAAoB,EAAE,GAAqB;QAC9D,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QACvC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,WAAW,CAAA;QAC5C,GAAG,CAAC,IAAI,CAAC;;;;SAIJ,KAAK;;;QAGN,CAAC,CAAA;IACP,CAAC;IAED;;;;;;OAMG;IACK,OAAO,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QACrF,MAAM,SAAS,GAAG,cAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QAClF,GAAG,CAAC,KAAK,CAAC,aAAa,SAAS,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QAC9C,MAAM,KAAK,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QACtD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,SAAS,YAAY,CAAC,CAAC,CAAA;QAClD,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAChD,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IAEO,cAAc,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QAC5F,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,KAAK,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC3C,IAAI,CAAC,YAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC,CAAA;QACvD,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,cAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QAC1F,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;QACjD,gBAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,cAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnD,CAAC;IAEO,QAAQ,CAAC,GAAoB,EAAE,GAAqB,EAAE,IAA0B;QACtF,MAAM,SAAS,GAAG,cAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QAClF,GAAG,CAAC,KAAK,CAAC,cAAc,SAAS,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;QAC1D,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,SAAS,YAAY,CAAC,CAAC,CAAA;QAClD,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAChD,CAAC;QACD,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,iBAAiB,CAAC,EAAU,EAAE,MAAqB;QAC/D,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAU,EAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QAChC,MAAM,aAAa,GAAG,IAAA,mCAAuB,EAAC,EAAE,CAAC,CAAA;QACjD,MAAM,WAAW,GAAG,IAAI,GAAG,aAAa,CAAC,SAAS,CAAA;QAElD,gCAAgC;QAChC,MAAM,UAAU,GAAgB,EAAE,CAAA;QAClC,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;YAC5B,KAAK,MAAM,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3D,MAAM,GAAG,GAAG,MAAM,IAAA,wBAAgB,EAAC,EAAE,GAAG,aAAa,EAAE,SAAS,EAAE,CAAC,CAAA;gBACnE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAEpF,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC,EAAE,GAAG,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;QAC5F,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACxB,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAA;YACnD,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,CAAA;QACxE,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACpC,MAAM,GAAG,CAAA;QACX,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,gBAAgB,CAAC,EAAU;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAA;YACpD,OAAM;QACR,CAAC;QACD,OAAO,CAAC,kBAAkB,EAAE,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAA;IACtB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAClB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,iBAAiB,CAAC,CAAA;YAC1D,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;YAChD,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;YAChD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvD,MAAM,IAAA,uBAAe,EACnB,YAAY,OAAO,mDAAmD,OAAO,yBAAyB,OAAO,qFAAqF,CACnM,CAAA;YACH,CAAC;YACD,IAAI,CAAC,MAAM,GAAG,IAAA,oBAAa,EACzB;gBACE,GAAG,EAAE,YAAE,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC7B,IAAI,EAAE,YAAE,CAAC,YAAY,CAAC,OAAO,CAAC;aAC/B,EACD,IAAI,CAAC,GAAG,CACT,CAAA;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,GAAG,IAAA,mBAAY,EAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACtC,CAAC;QAED,sBAAsB;QACtB,MAAM,GAAG,GAAG,IAAI,oBAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE;YACnC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;gBACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;gBACxC,GAAG,CAAC,KAAK,CAAC,sBAAsB,OAAO,CAAC,MAAM,CAAC,aAAa,YAAY,MAAM,EAAE,CAAC,CAAA;gBACjF,QAAQ,MAAM,EAAE,CAAC;oBACf,KAAK,cAAc,CAAC,CAAC,CAAC;wBACpB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;4BACrB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;wBAC9C,CAAC;wBACD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;wBAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;4BACd,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;wBACrC,CAAC;wBACD,MAAM,SAAS,GAAG,cAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;wBAE3E,GAAG,CAAC,KAAK,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAA;wBACzC,MAAM,KAAK,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;wBACtD,IAAI,YAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;4BACzB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAA;wBAClD,CAAC;wBACD,MAAM,MAAM,GAAG,YAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAA;wBAE1C,IAAI,aAAa,GAAG,KAAK,CAAA;wBACzB,IAAI,aAAa,GAAG,CAAC,CAAA;wBAErB,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;4BACvB,MAAM,CAAC,KAAK,EAAE,CAAA;4BACd,EAAE,CAAC,KAAK,EAAE,CAAA;4BAEV,IAAI,CAAC;gCACH,IAAI,CAAC,aAAa,EAAE,CAAC;oCACnB,MAAM,YAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gCACjC,CAAC;4BACH,CAAC;4BAAC,OAAO,GAAG,EAAE,CAAC;gCACb,GAAG,CAAC,KAAK,CAAC,gCAAiC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;4BACrE,CAAC;wBACH,CAAC,CAAA;wBAED,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;4BAChC,GAAG,CAAC,KAAK,CAAC,0BAA0B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;4BAClD,KAAK,KAAK,EAAE,CAAA;wBACd,CAAC,CAAC,CAAA;wBAEF,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;4BAC5B,GAAG,CAAC,KAAK,CAAC,0BAA0B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;4BAClD,KAAK,KAAK,EAAE,CAAA;wBACd,CAAC,CAAC,CAAA;wBAEF,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;4BAClB,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;4BAClC,KAAK,KAAK,EAAE,CAAA;wBACd,CAAC,CAAC,CAAA;wBAEF,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAgB,EAAE,EAAE;4BACpC,IAAI,CAAC,IAAI,EAAE,UAAU;gCAAE,OAAM;4BAC7B,IAAI,CAAC,aAAa,EAAE,CAAC;gCACnB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gCAClB,aAAa,GAAG,IAAI,CAAA;gCACpB,OAAM;4BACR,CAAC;4BACD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;4BAClB,aAAa,EAAE,CAAA;wBACjB,CAAC,CAAC,CAAA;wBAEF,MAAK;oBACP,CAAC;oBACD;wBACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAA;gBAChD,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,wBAAyB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC3D,EAAE,CAAC,KAAK,EAAE,CAAA;YACZ,CAAC;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QAEd,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YAClD,GAAG,CAAC,KAAK,CAAC,cAAc,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;YACtC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;gBACnE,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBAC9B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAA,wBAAe,EAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;oBACjF,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAA;gBACjC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,qBAAsB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;gBACxD,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAA;gBACjD,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,OAAM;YACR,CAAC;YAED,GAAG,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE;gBAC5C,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;YACrC,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE;YACvC,GAAG,CAAC,KAAK,CAAC,kCAAkC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;QAChE,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;YAChB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA;QACjB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACjB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;YACnB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QACpB,CAAC;IACH,CAAC;CACF;AA7nBD,wBA6nBC","sourcesContent":["import compression from 'compression'\nimport { timingSafeEqual } from 'crypto'\nimport express, { json } from 'express'\nimport fs from 'fs'\nimport { Server as HttpServer, createServer } from 'http'\nimport { Server as HttpsServer, createServer as _createServer } from 'https'\nimport os from 'os'\nimport path from 'path'\nimport tar from 'tar-fs'\nimport { WebSocketServer } from 'ws'\nimport zlib from 'zlib'\nimport auth from 'basic-auth'\n\nimport { Config, loadConfig } from './config'\nimport { Session, SessionParams } from './session'\nimport { Stats } from './stats'\nimport { logger, runShellCommand, getDockerLogsPath } from './utils'\nimport { getSessionThrottleIndex } from '@vpalmisano/throttler'\nimport { MediaPath, prepareFakeMedia } from './media'\n\nconst log = logger('webrtcperf:server')\n\n/**\n * An HTTP server instance that allows to control the tool using a REST\n * interface. Moreover, it allows to aggregate stats data coming from multiple\n * running tool instances.\n */\nexport class Server {\n /** The server listening port. */\n readonly serverPort: number\n /** The basic auth secret. */\n readonly serverSecret: string\n /** If HTTPS protocol should be used. */\n readonly serverUseHttps: boolean\n /** An optional path that the HTTP server will expose with the /data endpoint. */\n serverData: string\n /** The file path that will be used to serve the \\`/view/page.log\\` requests. */\n pageLogPath: string\n /** The path that will be used to serve the \\`/cache\\` requests. */\n videoCachePath: string\n /** A {@link Stats} class instance. */\n stats: Stats\n\n private app: express.Express\n private server: HttpServer | HttpsServer | null = null\n private wss: WebSocketServer | null = null\n\n /**\n * Server instance.\n * All the HTTP endpoints are protected by basic authentication with user\n * `admin` and password {@link Server.serverSecret}.\n * @param serverPort The server listening port.\n * @param serverSecret The basic auth secret.\n * @param serverUseHttps If HTTPS protocol should be used.\n * @param serverData An optional path that the HTTP server will expose with the /data endpoint.\n * @param pageLogPath The file path that will be used to serve the \\`/view/page.log\\` requests.\n * @param videoCachePath The path that will be used to serve the \\`/cache\\` requests.\n * @param stats A {@link Stats} class instance.\n */\n constructor(\n {\n serverPort = 5000,\n serverSecret = 'secret',\n serverUseHttps = false,\n serverData = '',\n pageLogPath = '',\n videoCachePath = '',\n } = {},\n stats: Stats,\n ) {\n this.serverPort = serverPort\n this.serverSecret = serverSecret\n this.serverUseHttps = serverUseHttps\n this.serverData = serverData\n this.pageLogPath = pageLogPath\n this.videoCachePath = videoCachePath\n this.stats = stats\n //\n this.app = express()\n this.app.use(compression())\n this.app.use(\n json({\n limit: '10mb',\n }),\n )\n\n this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {\n if (req.query.auth === this.serverSecret) {\n return next()\n }\n const credentials = auth(req)\n if (!credentials || credentials.name !== 'admin' || credentials.pass !== this.serverSecret) {\n res.setHeader('WWW-Authenticate', 'Basic realm=\"Restricted Area\"')\n res.status(401).send('Unauthorized')\n return\n }\n next()\n })\n\n this.app.get('/', (_req, res) => {\n res.send('')\n })\n\n this.app.get('/stats', this.getStats.bind(this))\n this.app.get('/collected-stats', this.getCollectedStats.bind(this))\n this.app.get('/screenshot/:sessionId', this.getScreenshot.bind(this))\n this.app.put('/collected-stats', this.putCollectedStats.bind(this))\n this.app.put('/session', this.putSession.bind(this))\n this.app.put('/sessions', this.putSessions.bind(this))\n this.app.delete('/session', this.deleteSession.bind(this))\n this.app.delete('/sessions', this.deleteSessions.bind(this))\n this.app.get('/view/page.log', this.getPageLog.bind(this))\n this.app.get('/view/docker.log', this.getDockerLog.bind(this))\n this.app.get('/download/alert-rules', this.getAlertRules.bind(this))\n this.app.get('/download/stats', this.getStatsFile.bind(this))\n this.app.get('/download/detailed-stats', this.getDetailedStatsFile.bind(this))\n this.app.get('/empty-page', this.getEmptyPage.bind(this))\n if (this.serverData) {\n log.debug(`using serverData: ${this.serverData}`)\n fs.promises.mkdir(this.serverData, { recursive: true }).catch(err => {\n log.error(`mkdir ${this.serverData} error: ${err.message}`)\n })\n this.app.get('/data', this.getDataArchive.bind(this))\n this.app.get('/data/:path', this.getData.bind(this))\n }\n if (this.videoCachePath) {\n log.debug(`using videoCachePath: ${this.videoCachePath}`)\n fs.promises.mkdir(this.videoCachePath, { recursive: true }).catch(err => {\n log.error(`mkdir ${this.videoCachePath} error: ${err.message}`)\n })\n this.app.get('/cache/:path', this.getCache.bind(this))\n }\n\n this.app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {\n log.error(`request path=${req.path} error:`, err.stack)\n if (res.headersSent) {\n return next(err)\n }\n res.status(500).send(err.message)\n })\n }\n\n /*\n * onConnection\n * @param {Socket} socket\n */\n /* onConnection(socket) {\n log.debug('onConnection', socket);\n\n socket.on('disconnect', () => {\n log.debug('io socket disconnected');\n });\n\n socket.on('message', (msg) => {\n log.debug('message', msg);\n });\n } */\n\n /**\n * GET /stats endpoint.\n *\n * Returns a JSON array of the last statistics for each running Session.\n */\n private async getStats(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`GET /stats`)\n const stats = []\n try {\n for (const session of this.stats.sessions.values()) {\n stats.push(session.stats)\n }\n res.json(stats)\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /download/stats endpoint.\n *\n * Returns the {@link Stats.statsWriter} file content.\n */\n private getStatsFile(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`/download/stats`, req.query)\n if (!this.stats.statsWriter) {\n return next(new Error('statsPath not set'))\n }\n res.download(this.stats.statsPath)\n }\n\n /**\n * GET /download/detailed-stats endpoint.\n *\n * Returns the {@link Stats.detailedStatsWriter} file content.\n */\n private getDetailedStatsFile(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`/download/detailed-stats`, req.query)\n if (!this.stats.detailedStatsWriter) {\n return next(new Error('detailedStatsPath not set'))\n }\n res.download(this.stats.detailedStatsPath)\n }\n\n /**\n * GET /collected-stats endpoint.\n *\n * Returns a JSON array of the last statistics collected from external running\n * tools.\n */\n private getCollectedStats(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /collected-stats`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stats: Record<string, any> = {}\n try {\n for (const [key, stat] of Object.entries(this.stats.collectedStats)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stats[key] = (stat as any).data\n }\n res.json(stats)\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /screenshot/<sessionID> endpoint.\n *\n * Returns the page screenshot running inside the {@link Session} identified\n * by `sessionID`.\n * Additional query params:\n * - `page`: the page number (starting from `0`) running inside the {@link Session}.\n * - `format`: the image format (`jpeg`, `png`, `webp`). Default: `webp`.\n */\n private async getScreenshot(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n const sessionId = parseInt(req.params.sessionId)\n const pageId = parseInt((req.query.page as string) || '0')\n const format = (req.query.format as string) || 'webp'\n log.debug(`GET /screenshot/${sessionId} page=${pageId} format=${format}`)\n try {\n const session = this.stats.sessions.get(sessionId)\n if (!session) {\n throw new Error(`Session not found: \"${sessionId}\"`)\n }\n const filePath = await session.pageScreenshot(pageId, format)\n res.sendFile(path.resolve(filePath))\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /collected-stats endpoint.\n *\n * Allows to inject {@link Stats} metrics coming from an external tool.\n */\n private putCollectedStats(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`PUT /collected-stats`)\n const { id, stats, config } = req.body\n try {\n this.stats.addExternalCollectedStats(id, stats, config)\n res.json({\n message: `Collected stats added`,\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /session endpoint.\n *\n * Starts a new {@link Session}.\n * The request body format will be parsed as a {@link SessionParams} object.\n */\n private async putSession(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`PUT /session`, req.body)\n try {\n const config = req.body as Config\n const id = this.stats.consumeSessionId(config.tabsPerSession)\n await this.startLocalSession(id, req.body)\n res.json({\n message: `Session created`,\n data: { id },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /sessions endpoint.\n *\n * Starts multiple {@link Session} instances as specified into the\n * `body.sessions` value.\n * The request body will be parsed as a {@link SessionParams} object.\n */\n private async putSessions(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`PUT /sessions`, req.body)\n try {\n const { sessions, tabsPerSession } = req.body as Config\n const sessionsIds = []\n for (let i = 0; i < sessions; i++) {\n const id = this.stats.consumeSessionId(tabsPerSession)\n await this.startLocalSession(id, req.body)\n sessionsIds.push(id)\n }\n res.json({\n message: `${sessions} sessions created`,\n data: { ids: sessionsIds },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * DELETE /session endpoint.\n *\n * Delete the {@link Session} instance identified by the `body.id` param.\n */\n private async deleteSession(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`DELETE /session`, req.body)\n try {\n const { id } = req.body\n await this.stopLocalSession(id)\n res.json({\n message: `Session deleted`,\n data: { id },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * DELETE /sessions endpoint.\n *\n * Delete the {@link Session} instances specified by the `body.ids` array.\n */\n private async deleteSessions(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`DELETE /sessions`, req.body)\n try {\n const { ids } = req.body\n for (const id of ids) {\n await this.stopLocalSession(id)\n }\n res.json({\n message: `${ids.length} sessions deleted`,\n data: { ids },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /view/page.log endpoint.\n *\n * Returns the page log file content as specified in {@link Config} `pageLogPath`.\n */\n private getPageLog(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /view/page.log`, req.query)\n if (!this.pageLogPath) {\n return next(new Error('pageLogPath not set'))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(path.resolve(this.pageLogPath))\n }\n\n /**\n * GET /view/docker.log endpoint.\n *\n * Returns the Docker logs related to the container running the tool.\n * It requires to run the Docker container with the following options:\n * ```\n --cidfile /tmp/docker.id\n -v /tmp/docker.id:/root/.webrtcperf/docker.id:ro\n -v /var/lib/docker:/var/lib/docker:ro\n * ```\n */\n private async getDockerLog(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`GET /view/docker.log`, req.query)\n try {\n const logPath = await getDockerLogsPath()\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(path.resolve(logPath))\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /download/alert-rules endpoint.\n *\n * Downloads the alert rules report stored into the {@link Stats.alertRulesOutput}.\n */\n private getAlertRules(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /download/alert-rules`, req.query)\n if (!this.stats.alertRulesOutput) {\n return next(new Error('Stats alertRulesOutput not set'))\n }\n res.download(this.stats.alertRulesOutput)\n }\n\n /**\n * GET /empty-page endpoint.\n *\n * Returns an empty HTML page. Useful for running tests with raw Javascript\n * content without any DOM rendering.\n */\n private getEmptyPage(req: express.Request, res: express.Response): void {\n log.debug(`GET /empty-page`, req.query)\n const title = req.query.title || 'EmptyPage'\n res.send(`<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${title}</title>\n</head>\n<body></body>\n</html>`)\n }\n\n /**\n * GET /data/* endpoint.\n *\n * Returns the file content relative to the {@link Config} `serverData` path.\n * If the requested path points to a directory, it returns the directory\n * content in tar.gz format.\n */\n private getData(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const paramPath = path.normalize(req.params.path).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n log.debug(`GET /data/${paramPath}`, req.query)\n const fpath = path.resolve(this.serverData, paramPath)\n if (!fs.existsSync(fpath)) {\n return next(new Error(`${paramPath} not found`))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(fpath)\n }\n\n private getDataArchive(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /data`, req.query)\n const fpath = path.resolve(this.serverData)\n if (!fs.lstatSync(fpath).isDirectory()) {\n return next(new Error(`${fpath} is not a directory`))\n }\n res.header('Content-Disposition', `attachment; filename=\"${path.basename(fpath)}.tar.gz\"`)\n res.setHeader('content-type', 'application/gzip')\n tar.pack(fpath).pipe(zlib.createGzip()).pipe(res)\n }\n\n private getCache(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const paramPath = path.normalize(req.params.path).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n log.debug(`GET /cache/${paramPath}`, req.query)\n const fpath = path.resolve(this.videoCachePath, paramPath)\n if (!fs.existsSync(fpath)) {\n return next(new Error(`${paramPath} not found`))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(fpath)\n }\n\n /**\n * Starts a new {@link Session} instance.\n * @param id The session unique id.\n * @param config The session configuration.\n */\n private async startLocalSession(id: number, config: SessionParams): Promise<Session> {\n const configs = await loadConfig(undefined, config)\n const sessionConfig = configs[0]\n const throttleIndex = getSessionThrottleIndex(id)\n const spawnPeriod = 1000 / sessionConfig.spawnRate\n\n // Prepare fake video and audio.\n const mediaPaths: MediaPath[] = []\n if (sessionConfig.videoPath) {\n for (const videoPath of sessionConfig.videoPath.split(',')) {\n const ret = await prepareFakeMedia({ ...sessionConfig, videoPath })\n mediaPaths.push(ret)\n }\n }\n const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined\n\n const session = new Session({ ...sessionConfig, throttleIndex, spawnPeriod, mediaPath, id })\n session.once('stop', () => {\n console.warn(`Session ${id} stopped, reloading...`)\n setTimeout(this.startLocalSession.bind(this), spawnPeriod, id, config)\n })\n this.stats.addSession(session)\n try {\n await session.start()\n } catch (err) {\n this.stats.removeSession(session.id)\n throw err\n }\n return session\n }\n\n /**\n * Stops a new {@link Session} instance.\n * @param {number} id The session unique id.\n */\n private async stopLocalSession(id: number): Promise<void> {\n const session = this.stats.sessions.get(id)\n if (!session) {\n log.warn(`stopLocalSession session ${id} not found`)\n return\n }\n session.removeAllListeners()\n this.stats.removeSession(id)\n await session.stop()\n }\n\n /**\n * Starts the {@link Server} instance.\n */\n async start(): Promise<void> {\n log.debug('start')\n if (this.serverUseHttps) {\n const destDir = path.join(os.homedir(), '.webrtcperf/ssl')\n const keyPath = path.join(destDir, 'domain.key')\n const crtPath = path.join(destDir, 'domain.crt')\n if (!fs.existsSync(keyPath) || !fs.existsSync(crtPath)) {\n await runShellCommand(\n `mkdir -p ${destDir} && openssl req -newkey rsa:2048 -nodes -keyout ${keyPath} -x509 -days 365 -out ${crtPath} -subj \"/C=EU/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com\"`,\n )\n }\n this.server = _createServer(\n {\n key: fs.readFileSync(keyPath),\n cert: fs.readFileSync(crtPath),\n },\n this.app,\n )\n } else {\n this.server = createServer(this.app)\n }\n\n // WebSocket endpoint.\n const wss = new WebSocketServer({ noServer: true })\n wss.on('connection', (ws, request) => {\n try {\n const query = new URLSearchParams(request.url?.split('?')[1] || '')\n const action = query.get('action') || ''\n log.debug(`ws connection from ${request.socket.remoteAddress} action: ${action}`)\n switch (action) {\n case 'write-stream': {\n if (!this.serverData) {\n throw new Error('serverData option not set')\n }\n const filename = query.get('filename') || ''\n if (!filename) {\n throw new Error('filename not set')\n }\n const paramPath = path.normalize(filename).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n\n log.debug(`ws write-stream ${paramPath}`)\n const fpath = path.resolve(this.serverData, paramPath)\n if (fs.existsSync(fpath)) {\n throw new Error(`file already exists: ${fpath}`)\n }\n const stream = fs.createWriteStream(fpath)\n\n let headerWritten = false\n let framesWritten = 0\n\n const close = async () => {\n stream.close()\n ws.close()\n\n try {\n if (!framesWritten) {\n await fs.promises.unlink(fpath)\n }\n } catch (err) {\n log.error(`ws write-stream close error: ${(err as Error).message}`)\n }\n }\n\n stream.on('error', (err: Error) => {\n log.error(`ws write-stream error: ${err.message}`)\n void close()\n })\n\n ws.on('error', (err: Error) => {\n log.error(`ws write-stream error: ${err.message}`)\n void close()\n })\n\n ws.on('close', () => {\n log.debug(`ws write-stream close`)\n void close()\n })\n\n ws.on('message', (data: Uint8Array) => {\n if (!data?.byteLength) return\n if (!headerWritten) {\n stream.write(data)\n headerWritten = true\n return\n }\n stream.write(data)\n framesWritten++\n })\n\n break\n }\n default:\n throw new Error(`invalid action: ${action}`)\n }\n } catch (err) {\n log.error(`ws connection error: ${(err as Error).message}`)\n ws.close()\n }\n })\n this.wss = wss\n\n this.server.on('upgrade', (request, socket, head) => {\n log.debug(`ws upgrade ${request.url}`)\n try {\n const query = new URLSearchParams(request.url?.split('?')[1] || '')\n const auth = query.get('auth')\n if (!auth || !timingSafeEqual(Buffer.from(auth), Buffer.from(this.serverSecret))) {\n throw new Error('invalid auth')\n }\n } catch (err) {\n log.error(`ws upgrade error: ${(err as Error).message}`)\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n')\n socket.destroy()\n return\n }\n\n wss.handleUpgrade(request, socket, head, ws => {\n wss.emit('connection', ws, request)\n })\n })\n\n this.server.listen(this.serverPort, () => {\n log.debug(`HTTPS server listening on port ${this.serverPort}`)\n })\n }\n\n /**\n * Stops the {@link Server} instance.\n */\n stop(): void {\n if (this.wss) {\n this.wss.close()\n this.wss = null\n }\n if (this.server) {\n log.debug('stop')\n this.server.close()\n this.server = null\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import compression from 'compression'\nimport { timingSafeEqual } from 'crypto'\nimport express, { json } from 'express'\nimport fs from 'fs'\nimport { Server as HttpServer, createServer } from 'http'\nimport { Server as HttpsServer, createServer as _createServer } from 'https'\nimport os from 'os'\nimport path from 'path'\nimport tar from 'tar-fs'\nimport { WebSocketServer } from 'ws'\nimport zlib from 'zlib'\nimport auth from 'basic-auth'\n\nimport { Config, loadConfig } from './config'\nimport { Session, SessionParams } from './session'\nimport { Stats } from './stats'\nimport { logger, runShellCommand, getDockerLogsPath } from './utils'\nimport { getSessionThrottleIndex } from '@vpalmisano/throttler'\nimport { MediaPath, prepareFakeMedia } from './media'\n\nconst log = logger('webrtcperf:server')\n\n/**\n * An HTTP server instance that allows to control the tool using a REST\n * interface. Moreover, it allows to aggregate stats data coming from multiple\n * running tool instances.\n */\nexport class Server {\n /** The server listening port. */\n readonly serverPort: number\n /** The basic auth secret. */\n readonly serverSecret: string\n /** If HTTPS protocol should be used. */\n readonly serverUseHttps: boolean\n /** An optional path that the HTTP server will expose with the /data endpoint. */\n serverData: string\n /** The file path that will be used to serve the \\`/view/page.log\\` requests. */\n pageLogPath: string\n /** The path that will be used to serve the \\`/cache\\` requests. */\n videoCachePath: string\n /** A {@link Stats} class instance. */\n stats: Stats\n\n private app: express.Express\n private server: HttpServer | HttpsServer | null = null\n private wss: WebSocketServer | null = null\n\n /**\n * Server instance.\n * All the HTTP endpoints are protected by basic authentication with user\n * `admin` and password {@link Server.serverSecret}.\n * @param serverPort The server listening port.\n * @param serverSecret The basic auth secret.\n * @param serverUseHttps If HTTPS protocol should be used.\n * @param serverData An optional path that the HTTP server will expose with the /data endpoint.\n * @param pageLogPath The file path that will be used to serve the \\`/view/page.log\\` requests.\n * @param videoCachePath The path that will be used to serve the \\`/cache\\` requests.\n * @param stats A {@link Stats} class instance.\n */\n constructor(\n {\n serverPort = 5000,\n serverSecret = 'secret',\n serverUseHttps = false,\n serverData = '',\n pageLogPath = '',\n videoCachePath = '',\n } = {},\n stats: Stats,\n ) {\n this.serverPort = serverPort\n this.serverSecret = serverSecret\n this.serverUseHttps = serverUseHttps\n this.serverData = serverData\n this.pageLogPath = pageLogPath\n this.videoCachePath = videoCachePath\n this.stats = stats\n //\n this.app = express()\n this.app.use(compression())\n this.app.use(\n json({\n limit: '10mb',\n }),\n )\n\n this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {\n if (req.query.auth === this.serverSecret) {\n return next()\n }\n const credentials = auth(req)\n if (!credentials || credentials.name !== 'admin' || credentials.pass !== this.serverSecret) {\n res.setHeader('WWW-Authenticate', 'Basic realm=\"Restricted Area\"')\n res.status(401).send('Unauthorized')\n return\n }\n next()\n })\n\n this.app.get('/', (_req, res) => {\n res.send('')\n })\n\n this.app.get('/stats', this.getStats.bind(this))\n this.app.get('/collected-stats', this.getCollectedStats.bind(this))\n this.app.get('/screenshot/:sessionId', this.getScreenshot.bind(this))\n this.app.put('/collected-stats', this.putCollectedStats.bind(this))\n this.app.put('/session', this.putSession.bind(this))\n this.app.put('/sessions', this.putSessions.bind(this))\n this.app.delete('/session', this.deleteSession.bind(this))\n this.app.delete('/sessions', this.deleteSessions.bind(this))\n this.app.get('/view/page.log', this.getPageLog.bind(this))\n this.app.get('/view/docker.log', this.getDockerLog.bind(this))\n this.app.get('/download/alert-rules', this.getAlertRules.bind(this))\n this.app.get('/download/stats', this.getStatsFile.bind(this))\n this.app.get('/download/detailed-stats', this.getDetailedStatsFile.bind(this))\n this.app.get('/empty-page', this.getEmptyPage.bind(this))\n if (this.serverData) {\n log.debug(`using serverData: ${this.serverData}`)\n fs.promises.mkdir(this.serverData, { recursive: true }).catch(err => {\n log.error(`mkdir ${this.serverData} error: ${err.message}`)\n })\n this.app.get('/data', this.getDataArchive.bind(this))\n this.app.get('/data/:path', this.getData.bind(this))\n }\n if (this.videoCachePath) {\n log.debug(`using videoCachePath: ${this.videoCachePath}`)\n fs.promises.mkdir(this.videoCachePath, { recursive: true }).catch(err => {\n log.error(`mkdir ${this.videoCachePath} error: ${err.message}`)\n })\n this.app.get('/cache/:path', this.getCache.bind(this))\n }\n\n this.app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {\n log.error(`request path=${req.path} error:`, err.stack)\n if (res.headersSent) {\n return next(err)\n }\n res.status(500).send(err.message)\n })\n }\n\n /*\n * onConnection\n * @param {Socket} socket\n */\n /* onConnection(socket) {\n log.debug('onConnection', socket);\n\n socket.on('disconnect', () => {\n log.debug('io socket disconnected');\n });\n\n socket.on('message', (msg) => {\n log.debug('message', msg);\n });\n } */\n\n /**\n * GET /stats endpoint.\n *\n * Returns a JSON array of the last statistics for each running Session.\n */\n private async getStats(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`GET /stats`)\n const stats = []\n try {\n for (const session of this.stats.sessions.values()) {\n stats.push(session.stats)\n }\n res.json(stats)\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /download/stats endpoint.\n *\n * Returns the {@link Stats.statsWriter} file content.\n */\n private getStatsFile(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`/download/stats`, req.query)\n if (!this.stats.statsWriter) {\n return next(new Error('statsPath not set'))\n }\n res.download(this.stats.statsPath)\n }\n\n /**\n * GET /download/detailed-stats endpoint.\n *\n * Returns the {@link Stats.detailedStatsWriter} file content.\n */\n private getDetailedStatsFile(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`/download/detailed-stats`, req.query)\n if (!this.stats.detailedStatsWriter) {\n return next(new Error('detailedStatsPath not set'))\n }\n res.download(this.stats.detailedStatsPath)\n }\n\n /**\n * GET /collected-stats endpoint.\n *\n * Returns a JSON array of the last statistics collected from external running\n * tools.\n */\n private getCollectedStats(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /collected-stats`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stats: Record<string, any> = {}\n try {\n for (const [key, stat] of Object.entries(this.stats.collectedStats)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stats[key] = (stat as any).data\n }\n res.json(stats)\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /screenshot/<sessionID> endpoint.\n *\n * Returns the page screenshot running inside the {@link Session} identified\n * by `sessionID`.\n * Additional query params:\n * - `page`: the page number (starting from `0`) running inside the {@link Session}.\n * - `format`: the image format (`jpeg`, `png`, `webp`). Default: `webp`.\n */\n private async getScreenshot(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n const sessionId = parseInt(req.params.sessionId)\n const pageId = parseInt((req.query.page as string) || '0')\n const format = (req.query.format as string) || 'webp'\n log.debug(`GET /screenshot/${sessionId} page=${pageId} format=${format}`)\n try {\n const session = this.stats.sessions.get(sessionId)\n if (!session) {\n throw new Error(`Session not found: \"${sessionId}\"`)\n }\n const filePath = await session.pageScreenshot(pageId, format)\n res.sendFile(path.resolve(filePath), { dotfiles: 'allow' })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /collected-stats endpoint.\n *\n * Allows to inject {@link Stats} metrics coming from an external tool.\n */\n private putCollectedStats(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`PUT /collected-stats`)\n const { id, stats, config } = req.body\n try {\n this.stats.addExternalCollectedStats(id, stats, config)\n res.json({\n message: `Collected stats added`,\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /session endpoint.\n *\n * Starts a new {@link Session}.\n * The request body format will be parsed as a {@link SessionParams} object.\n */\n private async putSession(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`PUT /session`, req.body)\n try {\n const config = req.body as Config\n const id = this.stats.consumeSessionId(config.tabsPerSession)\n await this.startLocalSession(id, req.body)\n res.json({\n message: `Session created`,\n data: { id },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * PUT /sessions endpoint.\n *\n * Starts multiple {@link Session} instances as specified into the\n * `body.sessions` value.\n * The request body will be parsed as a {@link SessionParams} object.\n */\n private async putSessions(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`PUT /sessions`, req.body)\n try {\n const { sessions, tabsPerSession } = req.body as Config\n const sessionsIds = []\n for (let i = 0; i < sessions; i++) {\n const id = this.stats.consumeSessionId(tabsPerSession)\n await this.startLocalSession(id, req.body)\n sessionsIds.push(id)\n }\n res.json({\n message: `${sessions} sessions created`,\n data: { ids: sessionsIds },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * DELETE /session endpoint.\n *\n * Delete the {@link Session} instance identified by the `body.id` param.\n */\n private async deleteSession(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`DELETE /session`, req.body)\n try {\n const { id } = req.body\n await this.stopLocalSession(id)\n res.json({\n message: `Session deleted`,\n data: { id },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * DELETE /sessions endpoint.\n *\n * Delete the {@link Session} instances specified by the `body.ids` array.\n */\n private async deleteSessions(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`DELETE /sessions`, req.body)\n try {\n const { ids } = req.body\n for (const id of ids) {\n await this.stopLocalSession(id)\n }\n res.json({\n message: `${ids.length} sessions deleted`,\n data: { ids },\n })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /view/page.log endpoint.\n *\n * Returns the page log file content as specified in {@link Config} `pageLogPath`.\n */\n private getPageLog(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /view/page.log`, req.query)\n if (!this.pageLogPath) {\n return next(new Error('pageLogPath not set'))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(path.resolve(this.pageLogPath), { dotfiles: 'allow' })\n }\n\n /**\n * GET /view/docker.log endpoint.\n *\n * Returns the Docker logs related to the container running the tool.\n * It requires to run the Docker container with the following options:\n * ```\n --cidfile /tmp/docker.id\n -v /tmp/docker.id:/root/.webrtcperf/docker.id:ro\n -v /var/lib/docker:/var/lib/docker:ro\n * ```\n */\n private async getDockerLog(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {\n log.debug(`GET /view/docker.log`, req.query)\n try {\n const logPath = await getDockerLogsPath()\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(path.resolve(logPath), { dotfiles: 'allow' })\n } catch (err) {\n next(err)\n }\n }\n\n /**\n * GET /download/alert-rules endpoint.\n *\n * Downloads the alert rules report stored into the {@link Stats.alertRulesOutput}.\n */\n private getAlertRules(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /download/alert-rules`, req.query)\n if (!this.stats.alertRulesOutput) {\n return next(new Error('Stats alertRulesOutput not set'))\n }\n res.download(this.stats.alertRulesOutput)\n }\n\n /**\n * GET /empty-page endpoint.\n *\n * Returns an empty HTML page. Useful for running tests with raw Javascript\n * content without any DOM rendering.\n */\n private getEmptyPage(req: express.Request, res: express.Response): void {\n log.debug(`GET /empty-page`, req.query)\n const title = req.query.title || 'EmptyPage'\n res.send(`<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${title}</title>\n</head>\n<body></body>\n</html>`)\n }\n\n /**\n * GET /data/* endpoint.\n *\n * Returns the file content relative to the {@link Config} `serverData` path.\n * If the requested path points to a directory, it returns the directory\n * content in tar.gz format.\n */\n private getData(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const paramPath = path.normalize(req.params.path).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n log.debug(`GET /data/${paramPath}`, req.query)\n const fpath = path.resolve(this.serverData, paramPath)\n if (!fs.existsSync(fpath)) {\n return next(new Error(`${paramPath} not found`))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(fpath, { dotfiles: 'allow' })\n }\n\n private getDataArchive(req: express.Request, res: express.Response, next: express.NextFunction): void {\n log.debug(`GET /data`, req.query)\n const fpath = path.resolve(this.serverData)\n if (!fs.lstatSync(fpath).isDirectory()) {\n return next(new Error(`${fpath} is not a directory`))\n }\n res.header('Content-Disposition', `attachment; filename=\"${path.basename(fpath)}.tar.gz\"`)\n res.setHeader('content-type', 'application/gzip')\n tar.pack(fpath).pipe(zlib.createGzip()).pipe(res)\n }\n\n private getCache(req: express.Request, res: express.Response, next: express.NextFunction): void {\n const paramPath = path.normalize(req.params.path).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n log.debug(`GET /cache/${paramPath}`, req.query)\n const fpath = path.resolve(this.videoCachePath, paramPath)\n if (!fs.existsSync(fpath)) {\n return next(new Error(`${paramPath} not found`))\n }\n if (req.query.range && !req.headers.range) {\n req.headers.range = `bytes=${req.query.range}`\n }\n res.sendFile(fpath, { dotfiles: 'allow' })\n }\n\n /**\n * Starts a new {@link Session} instance.\n * @param id The session unique id.\n * @param config The session configuration.\n */\n private async startLocalSession(id: number, config: SessionParams): Promise<Session> {\n const configs = await loadConfig(undefined, config)\n const sessionConfig = configs[0]\n const throttleIndex = getSessionThrottleIndex(id)\n const spawnPeriod = 1000 / sessionConfig.spawnRate\n\n // Prepare fake video and audio.\n const mediaPaths: MediaPath[] = []\n if (sessionConfig.videoPath) {\n for (const videoPath of sessionConfig.videoPath.split(',')) {\n const ret = await prepareFakeMedia({ ...sessionConfig, videoPath })\n mediaPaths.push(ret)\n }\n }\n const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined\n\n const session = new Session({ ...sessionConfig, throttleIndex, spawnPeriod, mediaPath, id })\n session.once('stop', () => {\n console.warn(`Session ${id} stopped, reloading...`)\n setTimeout(this.startLocalSession.bind(this), spawnPeriod, id, config)\n })\n this.stats.addSession(session)\n try {\n await session.start()\n } catch (err) {\n this.stats.removeSession(session.id)\n throw err\n }\n return session\n }\n\n /**\n * Stops a new {@link Session} instance.\n * @param {number} id The session unique id.\n */\n private async stopLocalSession(id: number): Promise<void> {\n const session = this.stats.sessions.get(id)\n if (!session) {\n log.warn(`stopLocalSession session ${id} not found`)\n return\n }\n session.removeAllListeners()\n this.stats.removeSession(id)\n await session.stop()\n }\n\n /**\n * Starts the {@link Server} instance.\n */\n async start(): Promise<void> {\n log.debug('start')\n if (this.serverUseHttps) {\n const destDir = path.join(os.homedir(), '.webrtcperf/ssl')\n const keyPath = path.join(destDir, 'domain.key')\n const crtPath = path.join(destDir, 'domain.crt')\n if (!fs.existsSync(keyPath) || !fs.existsSync(crtPath)) {\n await runShellCommand(\n `mkdir -p ${destDir} && openssl req -newkey rsa:2048 -nodes -keyout ${keyPath} -x509 -days 365 -out ${crtPath} -subj \"/C=EU/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com\"`,\n )\n }\n this.server = _createServer(\n {\n key: fs.readFileSync(keyPath),\n cert: fs.readFileSync(crtPath),\n },\n this.app,\n )\n } else {\n this.server = createServer(this.app)\n }\n\n // WebSocket endpoint.\n const wss = new WebSocketServer({ noServer: true })\n wss.on('connection', (ws, request) => {\n try {\n const query = new URLSearchParams(request.url?.split('?')[1] || '')\n const action = query.get('action') || ''\n log.debug(`ws connection from ${request.socket.remoteAddress} action: ${action}`)\n switch (action) {\n case 'write-stream': {\n if (!this.serverData) {\n throw new Error('serverData option not set')\n }\n const filename = query.get('filename') || ''\n if (!filename) {\n throw new Error('filename not set')\n }\n const paramPath = path.normalize(filename).replace(/^(\\.\\.(\\/|\\\\|$))+/, '')\n\n log.debug(`ws write-stream ${paramPath}`)\n const fpath = path.resolve(this.serverData, paramPath)\n if (fs.existsSync(fpath)) {\n throw new Error(`file already exists: ${fpath}`)\n }\n const stream = fs.createWriteStream(fpath)\n\n let headerWritten = false\n let framesWritten = 0\n\n const close = async () => {\n stream.close()\n ws.close()\n\n try {\n if (!framesWritten) {\n await fs.promises.unlink(fpath)\n }\n } catch (err) {\n log.error(`ws write-stream close error: ${(err as Error).message}`)\n }\n }\n\n stream.on('error', (err: Error) => {\n log.error(`ws write-stream error: ${err.message}`)\n void close()\n })\n\n ws.on('error', (err: Error) => {\n log.error(`ws write-stream error: ${err.message}`)\n void close()\n })\n\n ws.on('close', () => {\n log.debug(`ws write-stream close`)\n void close()\n })\n\n ws.on('message', (data: Uint8Array) => {\n if (!data?.byteLength) return\n if (!headerWritten) {\n stream.write(data)\n headerWritten = true\n return\n }\n stream.write(data)\n framesWritten++\n })\n\n break\n }\n default:\n throw new Error(`invalid action: ${action}`)\n }\n } catch (err) {\n log.error(`ws connection error: ${(err as Error).message}`)\n ws.close()\n }\n })\n this.wss = wss\n\n this.server.on('upgrade', (request, socket, head) => {\n log.debug(`ws upgrade ${request.url}`)\n try {\n const query = new URLSearchParams(request.url?.split('?')[1] || '')\n const auth = query.get('auth')\n if (!auth || !timingSafeEqual(Buffer.from(auth), Buffer.from(this.serverSecret))) {\n throw new Error('invalid auth')\n }\n } catch (err) {\n log.error(`ws upgrade error: ${(err as Error).message}`)\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n')\n socket.destroy()\n return\n }\n\n wss.handleUpgrade(request, socket, head, ws => {\n wss.emit('connection', ws, request)\n })\n })\n\n this.server.listen(this.serverPort, () => {\n log.debug(`HTTPS server listening on port ${this.serverPort}`)\n })\n }\n\n /**\n * Stops the {@link Server} instance.\n */\n stop(): void {\n if (this.wss) {\n this.wss.close()\n this.wss = null\n }\n if (this.server) {\n log.debug('stop')\n this.server.close()\n this.server = null\n }\n }\n}\n"]}
|
package/build/src/session.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export interface SessionParams {
|
|
|
79
79
|
useFakeMedia: boolean;
|
|
80
80
|
enableGpu: string;
|
|
81
81
|
enableBrowserLogging: string;
|
|
82
|
+
enableRtpDump: string;
|
|
82
83
|
startTimestamp: number;
|
|
83
84
|
sessions: number;
|
|
84
85
|
tabsPerSession: number;
|
|
@@ -146,6 +147,7 @@ export declare class Session extends EventEmitter {
|
|
|
146
147
|
private readonly useFakeMedia;
|
|
147
148
|
private readonly enableGpu;
|
|
148
149
|
private readonly enableBrowserLogging;
|
|
150
|
+
private readonly enableRtpDump;
|
|
149
151
|
private readonly startTimestamp;
|
|
150
152
|
private readonly sessions;
|
|
151
153
|
private readonly tabsPerSession;
|
|
@@ -246,7 +248,7 @@ export declare class Session extends EventEmitter {
|
|
|
246
248
|
pageErrors: number;
|
|
247
249
|
private screensharePage?;
|
|
248
250
|
private static readonly jsonFetchCache;
|
|
249
|
-
constructor({ chromiumUrl, chromiumPath, chromiumFieldTrials, windowWidth, windowHeight, deviceScaleFactor, display, url, urlQuery, customUrlHandler, customUrlHandlerFn, mediaPath, videoWidth, videoHeight, videoFramerate, useFakeMedia, enableGpu, enableBrowserLogging, startTimestamp, sessions, tabsPerSession, spawnPeriod, statsInterval, disabledVideoCodecs, localStorage, sessionStorage, clearCookies, scriptPath, showPageLog, pageLogFilter, pageLogPath, userAgent, id, throttleIndex, useBrowserThrottling, evaluateAfter, exposedFunctions, scriptParams, blockedUrls, extraHeaders, responseModifiers, downloadResponses, extraCSS, cookies, overridePermissions, hardwareConcurrency, debuggingPort, debuggingAddress, randomAudioPeriod, maxVideoDecoders, maxVideoDecodersRange, incognito, serverPort, serverSecret, serverUseHttps, emulateCpuThrottling, }: SessionParams);
|
|
251
|
+
constructor({ chromiumUrl, chromiumPath, chromiumFieldTrials, windowWidth, windowHeight, deviceScaleFactor, display, url, urlQuery, customUrlHandler, customUrlHandlerFn, mediaPath, videoWidth, videoHeight, videoFramerate, useFakeMedia, enableGpu, enableBrowserLogging, enableRtpDump, startTimestamp, sessions, tabsPerSession, spawnPeriod, statsInterval, disabledVideoCodecs, localStorage, sessionStorage, clearCookies, scriptPath, showPageLog, pageLogFilter, pageLogPath, userAgent, id, throttleIndex, useBrowserThrottling, evaluateAfter, exposedFunctions, scriptParams, blockedUrls, extraHeaders, responseModifiers, downloadResponses, extraCSS, cookies, overridePermissions, hardwareConcurrency, debuggingPort, debuggingAddress, randomAudioPeriod, maxVideoDecoders, maxVideoDecodersRange, incognito, serverPort, serverSecret, serverUseHttps, emulateCpuThrottling, }: SessionParams);
|
|
250
252
|
/**
|
|
251
253
|
* Returns the chromium browser launch args
|
|
252
254
|
* @return the args list
|
package/build/src/session.js
CHANGED
|
@@ -52,6 +52,7 @@ class Session extends events_1.default {
|
|
|
52
52
|
useFakeMedia;
|
|
53
53
|
enableGpu;
|
|
54
54
|
enableBrowserLogging;
|
|
55
|
+
enableRtpDump;
|
|
55
56
|
startTimestamp;
|
|
56
57
|
sessions;
|
|
57
58
|
tabsPerSession;
|
|
@@ -154,7 +155,7 @@ class Session extends events_1.default {
|
|
|
154
155
|
});
|
|
155
156
|
constructor({ chromiumUrl, chromiumPath, chromiumFieldTrials, windowWidth, windowHeight, deviceScaleFactor, display,
|
|
156
157
|
/* audioRedForOpus, */
|
|
157
|
-
url, urlQuery, customUrlHandler, customUrlHandlerFn, mediaPath, videoWidth, videoHeight, videoFramerate, useFakeMedia, enableGpu, enableBrowserLogging, startTimestamp, sessions, tabsPerSession, spawnPeriod, statsInterval, disabledVideoCodecs, localStorage, sessionStorage, clearCookies, scriptPath, showPageLog, pageLogFilter, pageLogPath, userAgent, id, throttleIndex, useBrowserThrottling, evaluateAfter, exposedFunctions, scriptParams, blockedUrls, extraHeaders, responseModifiers, downloadResponses, extraCSS, cookies, overridePermissions, hardwareConcurrency, debuggingPort, debuggingAddress, randomAudioPeriod, maxVideoDecoders, maxVideoDecodersRange, incognito, serverPort, serverSecret, serverUseHttps, emulateCpuThrottling, }) {
|
|
158
|
+
url, urlQuery, customUrlHandler, customUrlHandlerFn, mediaPath, videoWidth, videoHeight, videoFramerate, useFakeMedia, enableGpu, enableBrowserLogging, enableRtpDump, startTimestamp, sessions, tabsPerSession, spawnPeriod, statsInterval, disabledVideoCodecs, localStorage, sessionStorage, clearCookies, scriptPath, showPageLog, pageLogFilter, pageLogPath, userAgent, id, throttleIndex, useBrowserThrottling, evaluateAfter, exposedFunctions, scriptParams, blockedUrls, extraHeaders, responseModifiers, downloadResponses, extraCSS, cookies, overridePermissions, hardwareConcurrency, debuggingPort, debuggingAddress, randomAudioPeriod, maxVideoDecoders, maxVideoDecodersRange, incognito, serverPort, serverSecret, serverUseHttps, emulateCpuThrottling, }) {
|
|
158
159
|
super();
|
|
159
160
|
log.debug('constructor', { id });
|
|
160
161
|
this.id = id;
|
|
@@ -184,6 +185,7 @@ class Session extends events_1.default {
|
|
|
184
185
|
this.useFakeMedia = useFakeMedia;
|
|
185
186
|
this.enableGpu = enableGpu;
|
|
186
187
|
this.enableBrowserLogging = (0, utils_1.enabledForSession)(this.id, enableBrowserLogging);
|
|
188
|
+
this.enableRtpDump = (0, utils_1.enabledForSession)(this.id, enableRtpDump);
|
|
187
189
|
this.startTimestamp = startTimestamp || Date.now();
|
|
188
190
|
this.sessions = sessions || 1;
|
|
189
191
|
this.tabsPerSession = tabsPerSession || 1;
|
|
@@ -344,12 +346,15 @@ class Session extends events_1.default {
|
|
|
344
346
|
`--window-size=${this.windowWidth},${this.windowHeight}`,
|
|
345
347
|
];
|
|
346
348
|
let fieldTrials = this.chromiumFieldTrials || '';
|
|
347
|
-
if (this.
|
|
349
|
+
if (this.pageLogPath && this.enableBrowserLogging) {
|
|
348
350
|
const pageLogDir = path_1.default.dirname(this.pageLogPath);
|
|
349
351
|
const eventLogPath = path_1.default.resolve(pageLogDir, `webrtc-event-logging-${this.id}`);
|
|
350
352
|
fs_1.default.mkdirSync(eventLogPath, { recursive: true });
|
|
351
353
|
args.push('--enable-logging', '--vmodule=*/webrtc/*=5', '--v=0', `--webrtc-event-logging=${eventLogPath}`);
|
|
352
354
|
fieldTrials = 'WebRTC-RtcEventLogNewFormat/Disabled/' + fieldTrials;
|
|
355
|
+
if (this.enableRtpDump) {
|
|
356
|
+
fieldTrials = 'WebRTC-Debugging-RtpDump/Enabled/' + fieldTrials;
|
|
357
|
+
}
|
|
353
358
|
env.CHROME_LOG_FILE = path_1.default.resolve(pageLogDir, `chrome-${this.id}.log`);
|
|
354
359
|
}
|
|
355
360
|
if (this.maxVideoDecoders !== -1 && (0, utils_1.enabledForSession)(this.id, this.maxVideoDecodersRange)) {
|
|
@@ -1112,6 +1117,26 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
|
|
|
1112
1117
|
throttler_1.throttleNotifier.on('change', onThrottleChange);
|
|
1113
1118
|
page.once('close', () => throttler_1.throttleNotifier.off('change', onThrottleChange));
|
|
1114
1119
|
}
|
|
1120
|
+
if (this.pageLogPath && this.enableRtpDump) {
|
|
1121
|
+
page.once('close', async () => {
|
|
1122
|
+
const dirPath = path_1.default.dirname(this.pageLogPath);
|
|
1123
|
+
const logFilePath = path_1.default.join(dirPath, `chrome-${this.id}.log`);
|
|
1124
|
+
if (fs_1.default.existsSync(logFilePath)) {
|
|
1125
|
+
const pcapFilePath = path_1.default.join(dirPath, `chrome-${this.id}.pcap`);
|
|
1126
|
+
try {
|
|
1127
|
+
await (0, utils_1.runShellCommand)(`\
|
|
1128
|
+
grep RTP_DUMP ${logFilePath} | text2pcap -D -u 1000,2000 -t %H:%M:%S.%f - ${pcapFilePath};
|
|
1129
|
+
grep -v RTP_DUMP ${logFilePath} > ${logFilePath}.tmp;
|
|
1130
|
+
mv ${logFilePath}.tmp ${logFilePath};
|
|
1131
|
+
`);
|
|
1132
|
+
log.info(`rtp dump saved to: ${pcapFilePath}`);
|
|
1133
|
+
}
|
|
1134
|
+
catch (err) {
|
|
1135
|
+
log.error(`error converting rtp dump to pcap: ${err.stack}`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1115
1140
|
log.debug(`Page ${index + 1} "${url}" loaded in ${(Date.now() - pageLoadTime) / 1000}s`);
|
|
1116
1141
|
for (let i = 0; i < this.evaluateAfter.length; i++) {
|
|
1117
1142
|
await page.evaluate(
|