├── example ├── .babelrc ├── README.md ├── index.html ├── package.json ├── webpack.config.js └── src │ └── index.js ├── .babelrc ├── proto ├── magnet2torrent │ ├── magnet2torrent.proto │ ├── magnet2torrent_pb_service.js │ ├── magnet2torrent_pb.d.ts │ ├── magnet2torrent_pb_service.d.ts │ └── magnet2torrent_pb.js ├── download-progress │ ├── download-progress.proto │ ├── download-progress_pb.d.ts │ ├── download-progress_pb_service.d.ts │ ├── download-progress_pb_service.js │ └── download-progress_pb.js ├── url-store │ ├── url-store.proto │ ├── url-store_pb_service.js │ ├── url-store_pb_service.d.ts │ ├── url-store_pb.d.ts │ └── url-store_pb.js ├── abuse-store │ ├── abuse-store.proto │ ├── abuse-store_pb_service.js │ ├── abuse-store_pb_service.d.ts │ ├── abuse-store_pb.d.ts │ └── abuse-store_pb.js ├── torrent-store │ ├── torrent-store.proto │ ├── torrent-store_pb_service.js │ ├── torrent-store_pb_service.d.ts │ └── torrent-store_pb.d.ts └── torrent-web-seeder │ ├── torrent-web-seeder.proto │ ├── torrent-web-seeder_pb_service.d.ts │ ├── torrent-web-seeder_pb_service.js │ └── torrent-web-seeder_pb.d.ts ├── webpack.config.js ├── src ├── sdk │ ├── tracker.js │ ├── process.js │ ├── abuse.js │ ├── magnet.js │ ├── ext.js │ ├── seeder │ │ ├── downloadProgress.js │ │ └── stats.js │ ├── loader │ │ └── torrent │ │ │ └── resource.js │ ├── torrent.js │ ├── loader.js │ ├── seeder.js │ └── util.js └── index.js ├── .github └── FUNDING.yml ├── .eslintrc.js ├── LICENSE ├── .gitignore ├── package.json └── README.md /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | "@babel/plugin-proposal-class-properties", 5 | "@babel/transform-runtime" 6 | // "transform-decorators-legacy" 7 | ], 8 | "env": { 9 | "production": { 10 | // "presets": ["minify"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example usage 2 | 3 | 1. Install dependencies 4 | 5 | ```bash 6 | npm install 7 | ``` 8 | 9 | 2. Change `apiUrl` at `src/index.js` to yours 10 | 3. Rebuild `dist/index.js` with: 11 | 12 | ```bash 13 | npm run build 14 | ``` 15 | 16 | 4. Open `index.html` in your browser. 17 | -------------------------------------------------------------------------------- /proto/magnet2torrent/magnet2torrent.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service Magnet2Torrent { 4 | // Converts magnet uri to torrent file 5 | rpc Magnet2Torrent (Magnet2TorrentRequest) returns (Magnet2TorrentReply) {} 6 | } 7 | 8 | // The request message containing the magnet url 9 | message Magnet2TorrentRequest { 10 | string magnet = 1; 11 | } 12 | 13 | // The response message containing the torrent 14 | message Magnet2TorrentReply { 15 | bytes torrent = 1; 16 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'production', 5 | entry: './src/index.js', 6 | output: { 7 | path: path.resolve('dist'), 8 | filename: 'index.js', 9 | libraryTarget: 'commonjs2', 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js?$/, 15 | exclude: /(node_modules)/, 16 | use: 'babel-loader', 17 | }, 18 | ], 19 | }, 20 | node: { 21 | fs: 'empty', 22 | }, 23 | resolve: { 24 | extensions: ['.js'], 25 | }, 26 | }; -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Webtor Platform SDK Example 5 | 6 | 7 | Sintel.mp4
8 | The Fanimatrix.avi 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /src/sdk/tracker.js: -------------------------------------------------------------------------------- 1 | const Url = require('url-parse'); 2 | 3 | export default function(params, sdk) { 4 | const self = {params, sdk}; 5 | return { 6 | async url(metadata = {}, params = {}) { 7 | params = Object.assign(self.params, params); 8 | const url = new Url(params.apiUrl); 9 | const pathname = '/tracker/'; 10 | url.set('pathname', pathname); 11 | url.set('protocol', 'wss:'); 12 | const query = await self.sdk.util.makeQuery(metadata, params); 13 | url.set('query', query); 14 | return url; 15 | }, 16 | }; 17 | }; -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: pavel_tatarskiy 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /proto/download-progress/download-progress.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/webtor-io/download-progress;download_progress"; 4 | 5 | service DownloadProgress { 6 | // Get download stat 7 | rpc Stat (StatRequest) returns (StatReply) {} 8 | // Get download stat stream 9 | rpc StatStream (StatRequest) returns (stream StatReply) {} 10 | } 11 | 12 | // Stat request message 13 | message StatRequest { 14 | } 15 | 16 | // Stat response message 17 | message StatReply { 18 | enum Status { 19 | NOT_STARTED = 0; 20 | PENDING = 1; 21 | ACTIVE = 2; 22 | DONE = 3; 23 | FAILED = 4; 24 | } 25 | Status status = 1; 26 | int64 downloaded = 2; 27 | int64 rate = 3; 28 | int64 length = 4; 29 | } -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack", 9 | "watch": "webpack --watch" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "css-loader": "^5.2.0", 16 | "style-loader": "^2.0.0", 17 | "webpack": "^4.46.0", 18 | "webpack-cli": "^3.3.12" 19 | }, 20 | "dependencies": { 21 | "@babel/core": "^7.13.14", 22 | "@babel/preset-env": "^7.13.12", 23 | "@webtor/platform-sdk-js": "^0.2.14", 24 | "babel-loader": "^8.2.2", 25 | "video.js": "^7.11.4", 26 | "videojs-contrib-hls": "^5.15.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /proto/url-store/url-store.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package webtor.url_store; 4 | option go_package = "github.com/webtor-io/url-store;url_store"; 5 | 6 | service UrlStore { 7 | // Pushes url to the store 8 | rpc Push (PushRequest) returns (PushReply) {} 9 | 10 | // Check url existence in the store 11 | rpc Check (CheckRequest) returns (CheckReply) {} 12 | } 13 | 14 | // The push response message 15 | message PushReply { 16 | string hash = 1; 17 | } 18 | 19 | // The push request message 20 | message PushRequest { 21 | string url = 1; 22 | } 23 | 24 | // The check request message containing the infoHash 25 | message CheckRequest { 26 | string hash = 1; 27 | } 28 | 29 | // The check response message containing existance flag 30 | message CheckReply { 31 | bool exists = 1; 32 | } 33 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/index.js', 5 | output: { 6 | filename: 'index.js', 7 | path: path.resolve(__dirname, 'dist'), 8 | }, 9 | mode: 'production', 10 | node: { 11 | fs: 'empty' 12 | }, 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.js?$/, 17 | exclude: /(node_modules)/, 18 | use: 'babel-loader', 19 | }, 20 | { 21 | test: /\.css$/i, 22 | use: ['style-loader', 'css-loader'], 23 | }, 24 | ], 25 | }, 26 | // node: { 27 | // fs: 'empty', 28 | // }, 29 | // resolve: { 30 | // extensions: ['.js'], 31 | // }, 32 | }; -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // "extends": ["google", "plugin:vue/recommended"], 3 | "extends": ["google"], 4 | "parser": "babel-eslint", 5 | "parserOptions": { 6 | "sourceType": "module", 7 | "ecmaVersion": 8, 8 | "ecmaFeatures": { 9 | "experimentalObjectRestSpread": true 10 | } 11 | }, 12 | "rules": { 13 | "max-len": [2, 80, 4, {"ignoreUrls": true, "ignoreStrings": true, 14 | "ignoreComments": true, "ignoreTemplateLiterals": true}], 15 | "require-jsdoc": "off", 16 | "no-invalid-this": "off", 17 | "chai-expect/missing-assertion": 2, 18 | "chai-expect/terminating-properties": 1, 19 | "mocha/no-exclusive-tests": 2 20 | }, 21 | "plugins": [ 22 | "eslint-plugin-html", 23 | "mocha", 24 | "chai-expect", 25 | "vue" 26 | ] 27 | }; 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 webtor.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /proto/abuse-store/abuse-store.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service AbuseStore { 4 | // Pushes abuse to the store 5 | rpc Push (PushRequest) returns (PushReply) {} 6 | 7 | // Check abuse in the store for existence 8 | rpc Check (CheckRequest) returns (CheckReply) {} 9 | } 10 | 11 | // The push response message containing 12 | message PushReply { 13 | } 14 | 15 | // The push request message 16 | message PushRequest { 17 | string notice_id = 1; 18 | string infohash = 2; 19 | string filename = 3; 20 | string work = 4; 21 | int64 started_at = 5; 22 | string email = 6; 23 | string description = 7; 24 | string subject = 8; 25 | enum Cause { 26 | ILLEGAL_CONTENT = 0; 27 | MALWARE = 1; 28 | APP_ERROR = 2; 29 | QUESTION = 3; 30 | } 31 | Cause cause = 9; 32 | enum Source { 33 | MAIL = 0; 34 | FORM = 1; 35 | } 36 | Source source = 10; 37 | } 38 | 39 | // The check request message containing the infoHash 40 | message CheckRequest { 41 | string infohash = 1; 42 | } 43 | 44 | // The check response message containing existance flag 45 | message CheckReply { 46 | bool exists = 1; 47 | } 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .yalc 61 | 62 | .DS_Store 63 | 64 | example/node_modules/ -------------------------------------------------------------------------------- /proto/torrent-store/torrent-store.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service TorrentStore { 4 | // Pushes torrent to the store 5 | rpc Push (PushRequest) returns (PushReply) {} 6 | 7 | // Pulls torrent from the store 8 | rpc Pull (PullRequest) returns (PullReply) {} 9 | 10 | // Touch torrent in the store 11 | rpc Touch (TouchRequest) returns (TouchReply) {} 12 | } 13 | 14 | // The push response message containing info hash of the pushed torrent file 15 | message PushReply { 16 | string infoHash = 1; 17 | } 18 | 19 | // The push request message containing the torrent and expire duration is seconds 20 | message PushRequest { 21 | bytes torrent = 1; 22 | int32 expire = 2 [deprecated=true]; 23 | } 24 | 25 | // The pull request message containing the infoHash 26 | message PullRequest { 27 | string infoHash = 1; 28 | } 29 | 30 | // The pull response message containing the torrent 31 | message PullReply { 32 | bytes torrent = 1; 33 | } 34 | 35 | // The check request message containing the infoHash 36 | message CheckRequest { 37 | string infoHash = 1; 38 | } 39 | 40 | // The check response message containing existance flag 41 | message CheckReply { 42 | bool exists = 1; 43 | } 44 | 45 | // The touch response message 46 | message TouchReply { 47 | } 48 | 49 | // The touch request message containing the torrent and expire duration is seconds 50 | message TouchRequest { 51 | string infoHash = 1; 52 | int32 expire = 2 [deprecated=true]; 53 | } -------------------------------------------------------------------------------- /proto/torrent-web-seeder/torrent-web-seeder.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service TorrentWebSeeder { 4 | // Get file stat 5 | rpc Stat (StatRequest) returns (StatReply) {} 6 | // Get file stat stream 7 | rpc StatStream (StatRequest) returns (stream StatReply) {} 8 | // Get file list 9 | rpc Files (FilesRequest) returns (FilesReply) {} 10 | } 11 | 12 | // Stat request message 13 | message StatRequest { 14 | string path = 1; 15 | } 16 | 17 | // Stat response message 18 | message StatReply { 19 | int64 total = 1; 20 | int64 completed = 2; 21 | int32 peers = 3; 22 | enum Status { 23 | INITIALIZATION = 0; 24 | SEEDING = 1; 25 | IDLE = 2; 26 | TERMINATED = 3; 27 | WAITING_FOR_PEERS = 4; 28 | RESTORING = 5; 29 | BACKINGUP = 6; 30 | } 31 | Status status = 4; 32 | repeated Piece pieces = 5; 33 | int32 seeders = 6; 34 | int32 leechers = 7; 35 | } 36 | 37 | message Piece { 38 | int64 position = 1; 39 | bool complete = 2; 40 | enum Priority { 41 | NONE = 0; 42 | NORMAL = 1; 43 | HIGH = 2; 44 | READAHEAD = 3; 45 | NEXT = 4; 46 | NOW = 5; 47 | } 48 | Priority priority = 3; 49 | } 50 | 51 | // Files requst message 52 | message FilesRequest { 53 | } 54 | 55 | message File { 56 | string path = 1; 57 | } 58 | 59 | // Files reply message 60 | message FilesReply { 61 | repeated File files = 1; 62 | } 63 | -------------------------------------------------------------------------------- /src/sdk/process.js: -------------------------------------------------------------------------------- 1 | import {grpc} from '@improbable-eng/grpc-web'; 2 | 3 | const debug = require('debug')('webtor:sdk'); 4 | 5 | export default async function(client, request, onMessage, onEnd, metadata = {}, params = {}) { 6 | metadata['token'] = await params.getToken(); 7 | metadata['api-key'] = params.apiKey; 8 | let retryCount = 0; 9 | return new Promise(function(resolve, reject) { 10 | function process() { 11 | const c = client(); 12 | if (onMessage) { 13 | c.onMessage((message) => { 14 | debug('got message=%o', message.toObject()); 15 | onMessage(message.toObject(), resolve, reject); 16 | }); 17 | } 18 | if (onEnd) { 19 | c.onEnd(async (res) => { 20 | if ((res == grpc.Code.Unknown || res == grpc.Code.Unavailable) && params.retryInterval && params.retryLimit > 0 && retryCount < params.retryLimit) { 21 | debug('failed to get process request error=%o retry count=%o', res, retryCount); 22 | await (new Promise(resolve => setTimeout(resolve, params.retryInterval))); 23 | retryCount++; 24 | process(); 25 | } else { 26 | onEnd(res, resolve, reject); 27 | } 28 | }); 29 | } 30 | c.start(new grpc.Metadata(metadata)); 31 | c.send(request); 32 | c.finishSend(); 33 | } 34 | process(); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@webtor/platform-sdk-js", 3 | "version": "0.2.18", 4 | "description": "SDK for online torrent streaming", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/webtor-io/platform-sdk-js" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "build": "webpack --mode production", 13 | "watch": "webpack --watch", 14 | "protoc": "ls proto/ | xargs -I{} protoc --plugin='protoc-gen-ts=./node_modules/.bin/protoc-gen-ts' --js_out='import_style=commonjs_strict,binary:.' --ts_out='service=grpc-web:.' ./proto/{}/{}.proto" 15 | }, 16 | "keywords": [ 17 | "webtor", 18 | "torrent", 19 | "streaming", 20 | "sdk" 21 | ], 22 | "homepage": "https://webtor.io", 23 | "author": "Pavel Tatarskiy", 24 | "license": "MIT", 25 | "devDependencies": { 26 | "@babel/core": "^7.7.7", 27 | "@babel/plugin-proposal-class-properties": "^7.7.4", 28 | "@babel/plugin-transform-runtime": "^7.7.6", 29 | "@babel/preset-env": "^7.7.7", 30 | "babel-loader": "^8.0.6", 31 | "webpack": "^4.41.5", 32 | "webpack-cli": "^3.3.10" 33 | }, 34 | "dependencies": { 35 | "@babel/runtime": "^7.7.7", 36 | "@improbable-eng/grpc-web": "^0.12.0", 37 | "debug": "^4.3.3", 38 | "fetch-retry": "^3.1.0", 39 | "google-protobuf": "^3.11.2", 40 | "iso-639-1": "^2.1.0", 41 | "lodash": "^4.17.15", 42 | "md5": "^2.3.0", 43 | "mime": "^2.4.4", 44 | "parse-torrent": "^7.0.1", 45 | "path-parse": "^1.0.6", 46 | "url-parse": "^1.4.7" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/sdk/abuse.js: -------------------------------------------------------------------------------- 1 | import {AbuseStore} from '../../proto/abuse-store/abuse-store_pb_service'; 2 | import {PushRequest} from '../../proto/abuse-store/abuse-store_pb'; 3 | import {grpc} from '@improbable-eng/grpc-web'; 4 | import process from './process'; 5 | const debug = require('debug')('webtor:sdk:abuse'); 6 | 7 | export default function(params = {}) { 8 | const self = {params}; 9 | return { 10 | push(abuse, metadata = {}, params = {}) { 11 | params = Object.assign(self.params, params); 12 | const url = params.apiUrl + '/abuse'; 13 | debug('push abuse url=%s metadata=%o', url, metadata); 14 | const request = new PushRequest(); 15 | request.setSubject(abuse.subject); 16 | request.setDescription(abuse.description); 17 | request.setInfohash(abuse.infohash); 18 | request.setFilename(abuse.filename); 19 | request.setEmail(abuse.email); 20 | request.setWork(abuse.work); 21 | request.setCause(abuse.cause); 22 | request.setSource(PushRequest.Source.FORM); 23 | const client = () => grpc.client(AbuseStore.Push, { 24 | host: url, 25 | // transport: grpc.WebsocketTransport(), 26 | debug: params.grpcDebug, 27 | }); 28 | const onEnd = (res, resolve, reject) => { 29 | if (res === grpc.Code.OK) { 30 | debug('abuse stored'); 31 | resolve(); 32 | } else { 33 | reject('failed to push abuse code=' + res); 34 | } 35 | } 36 | return process(client, request, null, onEnd, metadata, params); 37 | }, 38 | }; 39 | }; -------------------------------------------------------------------------------- /src/sdk/magnet.js: -------------------------------------------------------------------------------- 1 | import {Magnet2Torrent} from '../../proto/magnet2torrent/magnet2torrent_pb_service'; 2 | import {Magnet2TorrentRequest} from '../../proto/magnet2torrent/magnet2torrent_pb'; 3 | import {grpc} from '@improbable-eng/grpc-web'; 4 | import process from './process'; 5 | import parseTorrent from 'parse-torrent'; 6 | const debug = require('debug')('webtor:sdk:magnet'); 7 | 8 | export default function(params = {}) { 9 | const self = {params}; 10 | return { 11 | fetchTorrent(magnet, metadata = {}, params = {}) { 12 | params = Object.assign(self.params, params); 13 | const url = params.apiUrl + '/magnet2torrent'; 14 | debug('fetch torrent magnet=%s url=%s metadata=%o', magnet, url, metadata); 15 | const request = new Magnet2TorrentRequest(); 16 | request.setMagnet(magnet); 17 | const client = () => grpc.client(Magnet2Torrent.Magnet2Torrent, { 18 | host: url, 19 | transport: grpc.WebsocketTransport(), 20 | debug: params.grpcDebug, 21 | }); 22 | const onMessage = (message, resolve, reject) => { 23 | if (message.torrent == '') { 24 | return reject('no torrent'); 25 | } 26 | let torrent = Buffer.from(message.torrent, 'base64'); 27 | torrent = parseTorrent(torrent); 28 | debug('and finally torrent=%o', torrent); 29 | resolve(torrent); 30 | } 31 | const onEnd = (res, resolve, reject) => { 32 | if (res !== grpc.Code.OK) { 33 | reject('failed to fetch torrent code=' + res); 34 | } 35 | } 36 | return process(client, request, onMessage, onEnd, metadata, params); 37 | }, 38 | }; 39 | }; -------------------------------------------------------------------------------- /src/sdk/ext.js: -------------------------------------------------------------------------------- 1 | const pathParse = require('path-parse'); 2 | const Url = require('url-parse'); 3 | 4 | export default function(params, sdk) { 5 | const self = {params, sdk}; 6 | return { 7 | async url(extUrl, metadata = {}, params = {}) { 8 | params = Object.assign(self.params, params); 9 | const url = new Url(params.apiUrl); 10 | let fileName = ""; 11 | if (params.fileName) { 12 | fileName = params.fileName; 13 | } else { 14 | fileName = pathParse(extUrl).base; 15 | } 16 | const encodedUrl = encodeURIComponent(btoa(extUrl)); 17 | const pathname = '/ext/' + encodedUrl + '/' + fileName; 18 | url.set('pathname', pathname); 19 | const query = await self.sdk.util.makeQuery(metadata, params); 20 | url.set('query', query); 21 | return url; 22 | }, 23 | async streamSubtitleUrl(extUrl, metadata = {}, params = {}) { 24 | const url = await this.url(extUrl, metadata, params); 25 | return self.sdk.util.streamSubtitleUrl(url); 26 | }, 27 | async streamUrl(extUrl, metadata = {}, params = {}) { 28 | params = Object.assign({}, this.params, params); 29 | let url = await this.url(extUrl, metadata, params); 30 | return self.sdk.util.streamUrl(url, metadata, params); 31 | }, 32 | async mediaInfo(extUrl, metadata = {}, params = {}) { 33 | const url = await this.url(extUrl, metadata, params); 34 | return await self.sdk.util.mediaInfo(url); 35 | }, 36 | async openSubtitles(extUrl, metadata = {}, params = {}) { 37 | const url = await this.url(extUrl, metadata, params); 38 | return await self.sdk.util.openSubtitles(url); 39 | }, 40 | }; 41 | }; -------------------------------------------------------------------------------- /proto/magnet2torrent/magnet2torrent_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/magnet2torrent/magnet2torrent.proto 3 | 4 | var proto_magnet2torrent_magnet2torrent_pb = require("../../proto/magnet2torrent/magnet2torrent_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var Magnet2Torrent = (function () { 8 | function Magnet2Torrent() {} 9 | Magnet2Torrent.serviceName = "Magnet2Torrent"; 10 | return Magnet2Torrent; 11 | }()); 12 | 13 | Magnet2Torrent.Magnet2Torrent = { 14 | methodName: "Magnet2Torrent", 15 | service: Magnet2Torrent, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentRequest, 19 | responseType: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentReply 20 | }; 21 | 22 | exports.Magnet2Torrent = Magnet2Torrent; 23 | 24 | function Magnet2TorrentClient(serviceHost, options) { 25 | this.serviceHost = serviceHost; 26 | this.options = options || {}; 27 | } 28 | 29 | Magnet2TorrentClient.prototype.magnet2Torrent = function magnet2Torrent(requestMessage, metadata, callback) { 30 | if (arguments.length === 2) { 31 | callback = arguments[1]; 32 | } 33 | var client = grpc.unary(Magnet2Torrent.Magnet2Torrent, { 34 | request: requestMessage, 35 | host: this.serviceHost, 36 | metadata: metadata, 37 | transport: this.options.transport, 38 | debug: this.options.debug, 39 | onEnd: function (response) { 40 | if (callback) { 41 | if (response.status !== grpc.Code.OK) { 42 | var err = new Error(response.statusMessage); 43 | err.code = response.status; 44 | err.metadata = response.trailers; 45 | callback(err, null); 46 | } else { 47 | callback(null, response.message); 48 | } 49 | } 50 | } 51 | }); 52 | return { 53 | cancel: function () { 54 | callback = null; 55 | client.close(); 56 | } 57 | }; 58 | }; 59 | 60 | exports.Magnet2TorrentClient = Magnet2TorrentClient; 61 | 62 | -------------------------------------------------------------------------------- /proto/magnet2torrent/magnet2torrent_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/magnet2torrent/magnet2torrent.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class Magnet2TorrentRequest extends jspb.Message { 7 | getMagnet(): string; 8 | setMagnet(value: string): void; 9 | 10 | serializeBinary(): Uint8Array; 11 | toObject(includeInstance?: boolean): Magnet2TorrentRequest.AsObject; 12 | static toObject(includeInstance: boolean, msg: Magnet2TorrentRequest): Magnet2TorrentRequest.AsObject; 13 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 14 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 15 | static serializeBinaryToWriter(message: Magnet2TorrentRequest, writer: jspb.BinaryWriter): void; 16 | static deserializeBinary(bytes: Uint8Array): Magnet2TorrentRequest; 17 | static deserializeBinaryFromReader(message: Magnet2TorrentRequest, reader: jspb.BinaryReader): Magnet2TorrentRequest; 18 | } 19 | 20 | export namespace Magnet2TorrentRequest { 21 | export type AsObject = { 22 | magnet: string, 23 | } 24 | } 25 | 26 | export class Magnet2TorrentReply extends jspb.Message { 27 | getTorrent(): Uint8Array | string; 28 | getTorrent_asU8(): Uint8Array; 29 | getTorrent_asB64(): string; 30 | setTorrent(value: Uint8Array | string): void; 31 | 32 | serializeBinary(): Uint8Array; 33 | toObject(includeInstance?: boolean): Magnet2TorrentReply.AsObject; 34 | static toObject(includeInstance: boolean, msg: Magnet2TorrentReply): Magnet2TorrentReply.AsObject; 35 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 36 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 37 | static serializeBinaryToWriter(message: Magnet2TorrentReply, writer: jspb.BinaryWriter): void; 38 | static deserializeBinary(bytes: Uint8Array): Magnet2TorrentReply; 39 | static deserializeBinaryFromReader(message: Magnet2TorrentReply, reader: jspb.BinaryReader): Magnet2TorrentReply; 40 | } 41 | 42 | export namespace Magnet2TorrentReply { 43 | export type AsObject = { 44 | torrent: Uint8Array | string, 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import torrent from './sdk/torrent'; 2 | import magnet from './sdk/magnet'; 3 | import abuse from './sdk/abuse'; 4 | import seeder from './sdk/seeder'; 5 | import tracker from './sdk/tracker'; 6 | import loader from './sdk/loader'; 7 | import util from './sdk/util'; 8 | import ext from './sdk/ext'; 9 | import throttle from 'lodash/throttle'; 10 | 11 | const defaultParams = { 12 | db: null, 13 | grpcDebug: false, 14 | retryInterval: 1000, 15 | retryLimit: 3, 16 | cache: false, 17 | multibitrate: false, 18 | vod: false, 19 | pools: { 20 | cache: [], 21 | seeder: [], 22 | transcoder: [], 23 | }, 24 | subdomains: false, 25 | async getToken() { 26 | return null; 27 | }, 28 | endpoints: { 29 | torrent: '/store' 30 | }, 31 | tokenRenewInterval: 60000, 32 | } 33 | 34 | function sdk(params = {}) { 35 | params = Object.assign(defaultParams, params); 36 | if (params.tokenUrl) { 37 | params.getToken = async () => { 38 | const res = await fetch(params.tokenUrl); 39 | return res.text(); 40 | } 41 | } 42 | if (params.tokenRenewInterval) { 43 | const t = params.getToken; 44 | params.getToken = throttle(t, params.tokenRenewInterval, { 45 | trailing: false, 46 | }); 47 | } 48 | 49 | let sdk = {}; 50 | 51 | sdk = Object.assign(sdk, { 52 | params, 53 | tracker: tracker(params, sdk), 54 | seeder: seeder(params, sdk), 55 | ext: ext(params, sdk), 56 | magnet: magnet(params, sdk), 57 | torrent: torrent(params, sdk), 58 | abuse: abuse(params, sdk), 59 | util: util(params, sdk), 60 | loader: loader(params, sdk), 61 | }); 62 | sdk.load = (source, metadata = {}, params = {}) => { 63 | return sdk.loader.load(source, metadata, params); 64 | }; 65 | sdk.loadById = (type, id, metadata = {}, params = {}) => { 66 | return sdk.loader.loadById(type, id, metadata, params); 67 | }; 68 | 69 | return sdk; 70 | 71 | }; 72 | 73 | export default function(params = {}) { 74 | return sdk(params); 75 | } -------------------------------------------------------------------------------- /src/sdk/seeder/downloadProgress.js: -------------------------------------------------------------------------------- 1 | import {DownloadProgress} from '../../../proto/download-progress/download-progress_pb_service'; 2 | import {StatRequest, StatReply} from '../../../proto/download-progress/download-progress_pb'; 3 | import {grpc} from '@improbable-eng/grpc-web'; 4 | import process from '../process'; 5 | const debug = require('debug')('webtor:sdk:seeder:downloadProgress'); 6 | import invert from 'lodash/invert'; 7 | 8 | class Stats { 9 | constructor(url, path) { 10 | this.url = url; 11 | this.path = path; 12 | this.closed = false; 13 | this.client = null; 14 | } 15 | close() { 16 | if (this.closed) return; 17 | this.closed = true; 18 | debug('close download progress url=%o path=%o', this.url, this.path); 19 | if (this.client) this.client.close(); 20 | } 21 | start(onMessage, onEnd, metadata, params) { 22 | const request = new StatRequest(); 23 | const client = () => { 24 | const c = grpc.client(DownloadProgress.StatStream, { 25 | host: this.url, 26 | transport: grpc.WebsocketTransport(), 27 | debug: params.grpcDebug, 28 | }); 29 | this.client = c; 30 | return c; 31 | }; 32 | const statuses = invert(StatReply.Status); 33 | const onMessageWrapper = (message) => { 34 | message.statusName = statuses[message.status]; 35 | onMessage(this.path, message); 36 | } 37 | const onEndWrapper = (res, resolve, reject) => { 38 | if (res !== grpc.Code.OK) { 39 | reject('failed to get download progress code=' + res); 40 | } else { 41 | debug('download progress finished url=%o path=%o', this.url, this.path); 42 | this.close(); 43 | resolve(); 44 | } 45 | onEnd(this.path, res); 46 | } 47 | 48 | return process(client, request, onMessageWrapper, onEndWrapper, metadata, params); 49 | } 50 | } 51 | 52 | export default function(url, path, onMessage, onEnd, metadata = {}, params = {}) { 53 | const st = new Stats(url, path); 54 | st.start(onMessage, onEnd, metadata, params); 55 | return st; 56 | } -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import webtor from '@webtor/platform-sdk-js'; 2 | import 'video.js/dist/video-js.css'; 3 | import videojs from 'video.js'; 4 | // import hls from 'videojs-contrib-hls'; 5 | const parseTorrent = require('parse-torrent'); 6 | 7 | async function main() { 8 | const links = document.querySelectorAll('a[data-magnet]'); 9 | for (const l of links) { 10 | l.addEventListener('click', function (e) { 11 | const m = e.target.getAttribute('data-magnet'); 12 | run(m); 13 | e.preventDefault(); 14 | return false; 15 | }); 16 | } 17 | } 18 | 19 | async function run(magnetUri) { 20 | const link = document.querySelector('#download'); 21 | link.setAttribute('target', '_blank'); 22 | link.innerHTML = 'loading...'; 23 | const status = document.querySelector('#status') 24 | status.innerHTML = ''; 25 | 26 | const sdk = webtor({ 27 | apiUrl: 'http://127.0.0.1:32476', // you should change this 28 | }); 29 | 30 | let torrent = parseTorrent(magnetUri); 31 | 32 | try { 33 | torrent = await sdk.torrent.pull(torrent.infoHash); 34 | } catch (e) { 35 | console.log(e); 36 | torrent = null; 37 | } 38 | 39 | if (!torrent) { 40 | torrent = await sdk.magnet.fetchTorrent(magnetUri); 41 | } 42 | 43 | const expire = 60*60*24; 44 | 45 | await sdk.torrent.push(torrent, expire); 46 | 47 | const seeder = sdk.seeder.get(torrent.infoHash); 48 | 49 | let filePath = null; 50 | 51 | for (const f of torrent.files) { 52 | if (sdk.util.getMediaType(f.path) == 'video') { 53 | filePath = f.path; 54 | } 55 | } 56 | 57 | const url = await seeder.streamUrl(filePath); 58 | 59 | const v = videojs("webtor"); 60 | v.src({ 61 | src: url.toString(), 62 | }); 63 | 64 | link.setAttribute('href', url.toString()); 65 | link.innerHTML = filePath; 66 | 67 | // NOTE: stats will become available only after content url access 68 | seeder.stats(filePath, (path, data) => { 69 | console.log(data); 70 | status.innerHTML = 'total: ' + data.total; 71 | status.innerHTML += ' completed: ' + data.completed; 72 | status.innerHTML += ' peers: ' + data.peers; 73 | }); 74 | } 75 | 76 | main(); -------------------------------------------------------------------------------- /proto/download-progress/download-progress_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/download-progress/download-progress.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class StatRequest extends jspb.Message { 7 | serializeBinary(): Uint8Array; 8 | toObject(includeInstance?: boolean): StatRequest.AsObject; 9 | static toObject(includeInstance: boolean, msg: StatRequest): StatRequest.AsObject; 10 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 11 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 12 | static serializeBinaryToWriter(message: StatRequest, writer: jspb.BinaryWriter): void; 13 | static deserializeBinary(bytes: Uint8Array): StatRequest; 14 | static deserializeBinaryFromReader(message: StatRequest, reader: jspb.BinaryReader): StatRequest; 15 | } 16 | 17 | export namespace StatRequest { 18 | export type AsObject = { 19 | } 20 | } 21 | 22 | export class StatReply extends jspb.Message { 23 | getStatus(): StatReply.StatusMap[keyof StatReply.StatusMap]; 24 | setStatus(value: StatReply.StatusMap[keyof StatReply.StatusMap]): void; 25 | 26 | getDownloaded(): number; 27 | setDownloaded(value: number): void; 28 | 29 | getRate(): number; 30 | setRate(value: number): void; 31 | 32 | getLength(): number; 33 | setLength(value: number): void; 34 | 35 | serializeBinary(): Uint8Array; 36 | toObject(includeInstance?: boolean): StatReply.AsObject; 37 | static toObject(includeInstance: boolean, msg: StatReply): StatReply.AsObject; 38 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 39 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 40 | static serializeBinaryToWriter(message: StatReply, writer: jspb.BinaryWriter): void; 41 | static deserializeBinary(bytes: Uint8Array): StatReply; 42 | static deserializeBinaryFromReader(message: StatReply, reader: jspb.BinaryReader): StatReply; 43 | } 44 | 45 | export namespace StatReply { 46 | export type AsObject = { 47 | status: StatReply.StatusMap[keyof StatReply.StatusMap], 48 | downloaded: number, 49 | rate: number, 50 | length: number, 51 | } 52 | 53 | export interface StatusMap { 54 | NOT_STARTED: 0; 55 | PENDING: 1; 56 | ACTIVE: 2; 57 | DONE: 3; 58 | FAILED: 4; 59 | } 60 | 61 | export const Status: StatusMap; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/sdk/seeder/stats.js: -------------------------------------------------------------------------------- 1 | import {TorrentWebSeeder} from '../../../proto/torrent-web-seeder/torrent-web-seeder_pb_service'; 2 | import {StatRequest, StatReply} from '../../../proto/torrent-web-seeder/torrent-web-seeder_pb'; 3 | import {grpc} from '@improbable-eng/grpc-web'; 4 | import process from '../process'; 5 | const debug = require('debug')('webtor:sdk:seeder:stats'); 6 | import invert from 'lodash/invert'; 7 | 8 | class Stats { 9 | constructor(url, path) { 10 | this.url = url; 11 | this.path = path; 12 | this.closed = false; 13 | this.client = null; 14 | } 15 | close() { 16 | if (this.closed) return; 17 | this.closed = true; 18 | debug('close stats url=%o path=%o', this.url, this.path); 19 | if (this.client) this.client.close(); 20 | } 21 | start(onMessage, metadata, params) { 22 | const request = new StatRequest(); 23 | request.setPath(this.path); 24 | const client = () => { 25 | const c = grpc.client(TorrentWebSeeder.StatStream, { 26 | host: this.url, 27 | transport: grpc.WebsocketTransport(), 28 | debug: params.grpcDebug, 29 | }); 30 | this.client = c; 31 | return c; 32 | }; 33 | const statuses = invert(StatReply.Status); 34 | let map = null; 35 | const onMessageWrapper = (message) => { 36 | message.statusName = statuses[message.status]; 37 | if (!map && message.status != 0) { 38 | map = message.piecesList; 39 | } else { 40 | for (const p of message.piecesList) { 41 | for (const m of map) { 42 | if (m.position == p.position) { 43 | m.complete = p.complete; 44 | m.priority = p.priority; 45 | } 46 | } 47 | } 48 | message.piecesList = JSON.parse(JSON.stringify(map)); 49 | } 50 | onMessage(this.path, message); 51 | } 52 | const onEnd = (res, resolve, reject) => { 53 | if (res !== grpc.Code.OK) { 54 | reject('failed to get stats torrent code=' + res); 55 | } else { 56 | debug('stats finished url=%o path=%o', this.url, this.path); 57 | this.close(); 58 | resolve(); 59 | } 60 | } 61 | 62 | return process(client, request, onMessageWrapper, onEnd, metadata, params); 63 | } 64 | } 65 | 66 | export default function(url, path, onMessage, metadata = {}, params = {}) { 67 | const stats = new Stats(url, path); 68 | stats.start(onMessage, metadata, params); 69 | return stats; 70 | } -------------------------------------------------------------------------------- /proto/magnet2torrent/magnet2torrent_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/magnet2torrent/magnet2torrent.proto 3 | 4 | import * as proto_magnet2torrent_magnet2torrent_pb from "../../proto/magnet2torrent/magnet2torrent_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type Magnet2TorrentMagnet2Torrent = { 8 | readonly methodName: string; 9 | readonly service: typeof Magnet2Torrent; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentRequest; 13 | readonly responseType: typeof proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentReply; 14 | }; 15 | 16 | export class Magnet2Torrent { 17 | static readonly serviceName: string; 18 | static readonly Magnet2Torrent: Magnet2TorrentMagnet2Torrent; 19 | } 20 | 21 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 22 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 23 | 24 | interface UnaryResponse { 25 | cancel(): void; 26 | } 27 | interface ResponseStream { 28 | cancel(): void; 29 | on(type: 'data', handler: (message: T) => void): ResponseStream; 30 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 31 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 32 | } 33 | interface RequestStream { 34 | write(message: T): RequestStream; 35 | end(): void; 36 | cancel(): void; 37 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 38 | on(type: 'status', handler: (status: Status) => void): RequestStream; 39 | } 40 | interface BidirectionalStream { 41 | write(message: ReqT): BidirectionalStream; 42 | end(): void; 43 | cancel(): void; 44 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 45 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 46 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 47 | } 48 | 49 | export class Magnet2TorrentClient { 50 | readonly serviceHost: string; 51 | 52 | constructor(serviceHost: string, options?: grpc.RpcOptions); 53 | magnet2Torrent( 54 | requestMessage: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentRequest, 55 | metadata: grpc.Metadata, 56 | callback: (error: ServiceError|null, responseMessage: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentReply|null) => void 57 | ): UnaryResponse; 58 | magnet2Torrent( 59 | requestMessage: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentRequest, 60 | callback: (error: ServiceError|null, responseMessage: proto_magnet2torrent_magnet2torrent_pb.Magnet2TorrentReply|null) => void 61 | ): UnaryResponse; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /proto/url-store/url-store_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: webtor.url_store 2 | // file: proto/url-store/url-store.proto 3 | 4 | var proto_url_store_url_store_pb = require("../../proto/url-store/url-store_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var UrlStore = (function () { 8 | function UrlStore() {} 9 | UrlStore.serviceName = "webtor.url_store.UrlStore"; 10 | return UrlStore; 11 | }()); 12 | 13 | UrlStore.Push = { 14 | methodName: "Push", 15 | service: UrlStore, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_url_store_url_store_pb.PushRequest, 19 | responseType: proto_url_store_url_store_pb.PushReply 20 | }; 21 | 22 | UrlStore.Check = { 23 | methodName: "Check", 24 | service: UrlStore, 25 | requestStream: false, 26 | responseStream: false, 27 | requestType: proto_url_store_url_store_pb.CheckRequest, 28 | responseType: proto_url_store_url_store_pb.CheckReply 29 | }; 30 | 31 | exports.UrlStore = UrlStore; 32 | 33 | function UrlStoreClient(serviceHost, options) { 34 | this.serviceHost = serviceHost; 35 | this.options = options || {}; 36 | } 37 | 38 | UrlStoreClient.prototype.push = function push(requestMessage, metadata, callback) { 39 | if (arguments.length === 2) { 40 | callback = arguments[1]; 41 | } 42 | var client = grpc.unary(UrlStore.Push, { 43 | request: requestMessage, 44 | host: this.serviceHost, 45 | metadata: metadata, 46 | transport: this.options.transport, 47 | debug: this.options.debug, 48 | onEnd: function (response) { 49 | if (callback) { 50 | if (response.status !== grpc.Code.OK) { 51 | var err = new Error(response.statusMessage); 52 | err.code = response.status; 53 | err.metadata = response.trailers; 54 | callback(err, null); 55 | } else { 56 | callback(null, response.message); 57 | } 58 | } 59 | } 60 | }); 61 | return { 62 | cancel: function () { 63 | callback = null; 64 | client.close(); 65 | } 66 | }; 67 | }; 68 | 69 | UrlStoreClient.prototype.check = function check(requestMessage, metadata, callback) { 70 | if (arguments.length === 2) { 71 | callback = arguments[1]; 72 | } 73 | var client = grpc.unary(UrlStore.Check, { 74 | request: requestMessage, 75 | host: this.serviceHost, 76 | metadata: metadata, 77 | transport: this.options.transport, 78 | debug: this.options.debug, 79 | onEnd: function (response) { 80 | if (callback) { 81 | if (response.status !== grpc.Code.OK) { 82 | var err = new Error(response.statusMessage); 83 | err.code = response.status; 84 | err.metadata = response.trailers; 85 | callback(err, null); 86 | } else { 87 | callback(null, response.message); 88 | } 89 | } 90 | } 91 | }); 92 | return { 93 | cancel: function () { 94 | callback = null; 95 | client.close(); 96 | } 97 | }; 98 | }; 99 | 100 | exports.UrlStoreClient = UrlStoreClient; 101 | 102 | -------------------------------------------------------------------------------- /proto/abuse-store/abuse-store_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/abuse-store/abuse-store.proto 3 | 4 | var proto_abuse_store_abuse_store_pb = require("../../proto/abuse-store/abuse-store_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var AbuseStore = (function () { 8 | function AbuseStore() {} 9 | AbuseStore.serviceName = "AbuseStore"; 10 | return AbuseStore; 11 | }()); 12 | 13 | AbuseStore.Push = { 14 | methodName: "Push", 15 | service: AbuseStore, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_abuse_store_abuse_store_pb.PushRequest, 19 | responseType: proto_abuse_store_abuse_store_pb.PushReply 20 | }; 21 | 22 | AbuseStore.Check = { 23 | methodName: "Check", 24 | service: AbuseStore, 25 | requestStream: false, 26 | responseStream: false, 27 | requestType: proto_abuse_store_abuse_store_pb.CheckRequest, 28 | responseType: proto_abuse_store_abuse_store_pb.CheckReply 29 | }; 30 | 31 | exports.AbuseStore = AbuseStore; 32 | 33 | function AbuseStoreClient(serviceHost, options) { 34 | this.serviceHost = serviceHost; 35 | this.options = options || {}; 36 | } 37 | 38 | AbuseStoreClient.prototype.push = function push(requestMessage, metadata, callback) { 39 | if (arguments.length === 2) { 40 | callback = arguments[1]; 41 | } 42 | var client = grpc.unary(AbuseStore.Push, { 43 | request: requestMessage, 44 | host: this.serviceHost, 45 | metadata: metadata, 46 | transport: this.options.transport, 47 | debug: this.options.debug, 48 | onEnd: function (response) { 49 | if (callback) { 50 | if (response.status !== grpc.Code.OK) { 51 | var err = new Error(response.statusMessage); 52 | err.code = response.status; 53 | err.metadata = response.trailers; 54 | callback(err, null); 55 | } else { 56 | callback(null, response.message); 57 | } 58 | } 59 | } 60 | }); 61 | return { 62 | cancel: function () { 63 | callback = null; 64 | client.close(); 65 | } 66 | }; 67 | }; 68 | 69 | AbuseStoreClient.prototype.check = function check(requestMessage, metadata, callback) { 70 | if (arguments.length === 2) { 71 | callback = arguments[1]; 72 | } 73 | var client = grpc.unary(AbuseStore.Check, { 74 | request: requestMessage, 75 | host: this.serviceHost, 76 | metadata: metadata, 77 | transport: this.options.transport, 78 | debug: this.options.debug, 79 | onEnd: function (response) { 80 | if (callback) { 81 | if (response.status !== grpc.Code.OK) { 82 | var err = new Error(response.statusMessage); 83 | err.code = response.status; 84 | err.metadata = response.trailers; 85 | callback(err, null); 86 | } else { 87 | callback(null, response.message); 88 | } 89 | } 90 | } 91 | }); 92 | return { 93 | cancel: function () { 94 | callback = null; 95 | client.close(); 96 | } 97 | }; 98 | }; 99 | 100 | exports.AbuseStoreClient = AbuseStoreClient; 101 | 102 | -------------------------------------------------------------------------------- /proto/download-progress/download-progress_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/download-progress/download-progress.proto 3 | 4 | import * as proto_download_progress_download_progress_pb from "../../proto/download-progress/download-progress_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type DownloadProgressStat = { 8 | readonly methodName: string; 9 | readonly service: typeof DownloadProgress; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_download_progress_download_progress_pb.StatRequest; 13 | readonly responseType: typeof proto_download_progress_download_progress_pb.StatReply; 14 | }; 15 | 16 | type DownloadProgressStatStream = { 17 | readonly methodName: string; 18 | readonly service: typeof DownloadProgress; 19 | readonly requestStream: false; 20 | readonly responseStream: true; 21 | readonly requestType: typeof proto_download_progress_download_progress_pb.StatRequest; 22 | readonly responseType: typeof proto_download_progress_download_progress_pb.StatReply; 23 | }; 24 | 25 | export class DownloadProgress { 26 | static readonly serviceName: string; 27 | static readonly Stat: DownloadProgressStat; 28 | static readonly StatStream: DownloadProgressStatStream; 29 | } 30 | 31 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 32 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 33 | 34 | interface UnaryResponse { 35 | cancel(): void; 36 | } 37 | interface ResponseStream { 38 | cancel(): void; 39 | on(type: 'data', handler: (message: T) => void): ResponseStream; 40 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 41 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 42 | } 43 | interface RequestStream { 44 | write(message: T): RequestStream; 45 | end(): void; 46 | cancel(): void; 47 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 48 | on(type: 'status', handler: (status: Status) => void): RequestStream; 49 | } 50 | interface BidirectionalStream { 51 | write(message: ReqT): BidirectionalStream; 52 | end(): void; 53 | cancel(): void; 54 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 55 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 56 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 57 | } 58 | 59 | export class DownloadProgressClient { 60 | readonly serviceHost: string; 61 | 62 | constructor(serviceHost: string, options?: grpc.RpcOptions); 63 | stat( 64 | requestMessage: proto_download_progress_download_progress_pb.StatRequest, 65 | metadata: grpc.Metadata, 66 | callback: (error: ServiceError|null, responseMessage: proto_download_progress_download_progress_pb.StatReply|null) => void 67 | ): UnaryResponse; 68 | stat( 69 | requestMessage: proto_download_progress_download_progress_pb.StatRequest, 70 | callback: (error: ServiceError|null, responseMessage: proto_download_progress_download_progress_pb.StatReply|null) => void 71 | ): UnaryResponse; 72 | statStream(requestMessage: proto_download_progress_download_progress_pb.StatRequest, metadata?: grpc.Metadata): ResponseStream; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /proto/url-store/url-store_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: webtor.url_store 2 | // file: proto/url-store/url-store.proto 3 | 4 | import * as proto_url_store_url_store_pb from "../../proto/url-store/url-store_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type UrlStorePush = { 8 | readonly methodName: string; 9 | readonly service: typeof UrlStore; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_url_store_url_store_pb.PushRequest; 13 | readonly responseType: typeof proto_url_store_url_store_pb.PushReply; 14 | }; 15 | 16 | type UrlStoreCheck = { 17 | readonly methodName: string; 18 | readonly service: typeof UrlStore; 19 | readonly requestStream: false; 20 | readonly responseStream: false; 21 | readonly requestType: typeof proto_url_store_url_store_pb.CheckRequest; 22 | readonly responseType: typeof proto_url_store_url_store_pb.CheckReply; 23 | }; 24 | 25 | export class UrlStore { 26 | static readonly serviceName: string; 27 | static readonly Push: UrlStorePush; 28 | static readonly Check: UrlStoreCheck; 29 | } 30 | 31 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 32 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 33 | 34 | interface UnaryResponse { 35 | cancel(): void; 36 | } 37 | interface ResponseStream { 38 | cancel(): void; 39 | on(type: 'data', handler: (message: T) => void): ResponseStream; 40 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 41 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 42 | } 43 | interface RequestStream { 44 | write(message: T): RequestStream; 45 | end(): void; 46 | cancel(): void; 47 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 48 | on(type: 'status', handler: (status: Status) => void): RequestStream; 49 | } 50 | interface BidirectionalStream { 51 | write(message: ReqT): BidirectionalStream; 52 | end(): void; 53 | cancel(): void; 54 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 55 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 56 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 57 | } 58 | 59 | export class UrlStoreClient { 60 | readonly serviceHost: string; 61 | 62 | constructor(serviceHost: string, options?: grpc.RpcOptions); 63 | push( 64 | requestMessage: proto_url_store_url_store_pb.PushRequest, 65 | metadata: grpc.Metadata, 66 | callback: (error: ServiceError|null, responseMessage: proto_url_store_url_store_pb.PushReply|null) => void 67 | ): UnaryResponse; 68 | push( 69 | requestMessage: proto_url_store_url_store_pb.PushRequest, 70 | callback: (error: ServiceError|null, responseMessage: proto_url_store_url_store_pb.PushReply|null) => void 71 | ): UnaryResponse; 72 | check( 73 | requestMessage: proto_url_store_url_store_pb.CheckRequest, 74 | metadata: grpc.Metadata, 75 | callback: (error: ServiceError|null, responseMessage: proto_url_store_url_store_pb.CheckReply|null) => void 76 | ): UnaryResponse; 77 | check( 78 | requestMessage: proto_url_store_url_store_pb.CheckRequest, 79 | callback: (error: ServiceError|null, responseMessage: proto_url_store_url_store_pb.CheckReply|null) => void 80 | ): UnaryResponse; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /proto/abuse-store/abuse-store_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/abuse-store/abuse-store.proto 3 | 4 | import * as proto_abuse_store_abuse_store_pb from "../../proto/abuse-store/abuse-store_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type AbuseStorePush = { 8 | readonly methodName: string; 9 | readonly service: typeof AbuseStore; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_abuse_store_abuse_store_pb.PushRequest; 13 | readonly responseType: typeof proto_abuse_store_abuse_store_pb.PushReply; 14 | }; 15 | 16 | type AbuseStoreCheck = { 17 | readonly methodName: string; 18 | readonly service: typeof AbuseStore; 19 | readonly requestStream: false; 20 | readonly responseStream: false; 21 | readonly requestType: typeof proto_abuse_store_abuse_store_pb.CheckRequest; 22 | readonly responseType: typeof proto_abuse_store_abuse_store_pb.CheckReply; 23 | }; 24 | 25 | export class AbuseStore { 26 | static readonly serviceName: string; 27 | static readonly Push: AbuseStorePush; 28 | static readonly Check: AbuseStoreCheck; 29 | } 30 | 31 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 32 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 33 | 34 | interface UnaryResponse { 35 | cancel(): void; 36 | } 37 | interface ResponseStream { 38 | cancel(): void; 39 | on(type: 'data', handler: (message: T) => void): ResponseStream; 40 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 41 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 42 | } 43 | interface RequestStream { 44 | write(message: T): RequestStream; 45 | end(): void; 46 | cancel(): void; 47 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 48 | on(type: 'status', handler: (status: Status) => void): RequestStream; 49 | } 50 | interface BidirectionalStream { 51 | write(message: ReqT): BidirectionalStream; 52 | end(): void; 53 | cancel(): void; 54 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 55 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 56 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 57 | } 58 | 59 | export class AbuseStoreClient { 60 | readonly serviceHost: string; 61 | 62 | constructor(serviceHost: string, options?: grpc.RpcOptions); 63 | push( 64 | requestMessage: proto_abuse_store_abuse_store_pb.PushRequest, 65 | metadata: grpc.Metadata, 66 | callback: (error: ServiceError|null, responseMessage: proto_abuse_store_abuse_store_pb.PushReply|null) => void 67 | ): UnaryResponse; 68 | push( 69 | requestMessage: proto_abuse_store_abuse_store_pb.PushRequest, 70 | callback: (error: ServiceError|null, responseMessage: proto_abuse_store_abuse_store_pb.PushReply|null) => void 71 | ): UnaryResponse; 72 | check( 73 | requestMessage: proto_abuse_store_abuse_store_pb.CheckRequest, 74 | metadata: grpc.Metadata, 75 | callback: (error: ServiceError|null, responseMessage: proto_abuse_store_abuse_store_pb.CheckReply|null) => void 76 | ): UnaryResponse; 77 | check( 78 | requestMessage: proto_abuse_store_abuse_store_pb.CheckRequest, 79 | callback: (error: ServiceError|null, responseMessage: proto_abuse_store_abuse_store_pb.CheckReply|null) => void 80 | ): UnaryResponse; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /proto/url-store/url-store_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: webtor.url_store 2 | // file: proto/url-store/url-store.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class PushReply extends jspb.Message { 7 | getHash(): string; 8 | setHash(value: string): void; 9 | 10 | serializeBinary(): Uint8Array; 11 | toObject(includeInstance?: boolean): PushReply.AsObject; 12 | static toObject(includeInstance: boolean, msg: PushReply): PushReply.AsObject; 13 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 14 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 15 | static serializeBinaryToWriter(message: PushReply, writer: jspb.BinaryWriter): void; 16 | static deserializeBinary(bytes: Uint8Array): PushReply; 17 | static deserializeBinaryFromReader(message: PushReply, reader: jspb.BinaryReader): PushReply; 18 | } 19 | 20 | export namespace PushReply { 21 | export type AsObject = { 22 | hash: string, 23 | } 24 | } 25 | 26 | export class PushRequest extends jspb.Message { 27 | getUrl(): string; 28 | setUrl(value: string): void; 29 | 30 | serializeBinary(): Uint8Array; 31 | toObject(includeInstance?: boolean): PushRequest.AsObject; 32 | static toObject(includeInstance: boolean, msg: PushRequest): PushRequest.AsObject; 33 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 34 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 35 | static serializeBinaryToWriter(message: PushRequest, writer: jspb.BinaryWriter): void; 36 | static deserializeBinary(bytes: Uint8Array): PushRequest; 37 | static deserializeBinaryFromReader(message: PushRequest, reader: jspb.BinaryReader): PushRequest; 38 | } 39 | 40 | export namespace PushRequest { 41 | export type AsObject = { 42 | url: string, 43 | } 44 | } 45 | 46 | export class CheckRequest extends jspb.Message { 47 | getHash(): string; 48 | setHash(value: string): void; 49 | 50 | serializeBinary(): Uint8Array; 51 | toObject(includeInstance?: boolean): CheckRequest.AsObject; 52 | static toObject(includeInstance: boolean, msg: CheckRequest): CheckRequest.AsObject; 53 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 54 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 55 | static serializeBinaryToWriter(message: CheckRequest, writer: jspb.BinaryWriter): void; 56 | static deserializeBinary(bytes: Uint8Array): CheckRequest; 57 | static deserializeBinaryFromReader(message: CheckRequest, reader: jspb.BinaryReader): CheckRequest; 58 | } 59 | 60 | export namespace CheckRequest { 61 | export type AsObject = { 62 | hash: string, 63 | } 64 | } 65 | 66 | export class CheckReply extends jspb.Message { 67 | getExists(): boolean; 68 | setExists(value: boolean): void; 69 | 70 | serializeBinary(): Uint8Array; 71 | toObject(includeInstance?: boolean): CheckReply.AsObject; 72 | static toObject(includeInstance: boolean, msg: CheckReply): CheckReply.AsObject; 73 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 74 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 75 | static serializeBinaryToWriter(message: CheckReply, writer: jspb.BinaryWriter): void; 76 | static deserializeBinary(bytes: Uint8Array): CheckReply; 77 | static deserializeBinaryFromReader(message: CheckReply, reader: jspb.BinaryReader): CheckReply; 78 | } 79 | 80 | export namespace CheckReply { 81 | export type AsObject = { 82 | exists: boolean, 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /proto/download-progress/download-progress_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/download-progress/download-progress.proto 3 | 4 | var proto_download_progress_download_progress_pb = require("../../proto/download-progress/download-progress_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var DownloadProgress = (function () { 8 | function DownloadProgress() {} 9 | DownloadProgress.serviceName = "DownloadProgress"; 10 | return DownloadProgress; 11 | }()); 12 | 13 | DownloadProgress.Stat = { 14 | methodName: "Stat", 15 | service: DownloadProgress, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_download_progress_download_progress_pb.StatRequest, 19 | responseType: proto_download_progress_download_progress_pb.StatReply 20 | }; 21 | 22 | DownloadProgress.StatStream = { 23 | methodName: "StatStream", 24 | service: DownloadProgress, 25 | requestStream: false, 26 | responseStream: true, 27 | requestType: proto_download_progress_download_progress_pb.StatRequest, 28 | responseType: proto_download_progress_download_progress_pb.StatReply 29 | }; 30 | 31 | exports.DownloadProgress = DownloadProgress; 32 | 33 | function DownloadProgressClient(serviceHost, options) { 34 | this.serviceHost = serviceHost; 35 | this.options = options || {}; 36 | } 37 | 38 | DownloadProgressClient.prototype.stat = function stat(requestMessage, metadata, callback) { 39 | if (arguments.length === 2) { 40 | callback = arguments[1]; 41 | } 42 | var client = grpc.unary(DownloadProgress.Stat, { 43 | request: requestMessage, 44 | host: this.serviceHost, 45 | metadata: metadata, 46 | transport: this.options.transport, 47 | debug: this.options.debug, 48 | onEnd: function (response) { 49 | if (callback) { 50 | if (response.status !== grpc.Code.OK) { 51 | var err = new Error(response.statusMessage); 52 | err.code = response.status; 53 | err.metadata = response.trailers; 54 | callback(err, null); 55 | } else { 56 | callback(null, response.message); 57 | } 58 | } 59 | } 60 | }); 61 | return { 62 | cancel: function () { 63 | callback = null; 64 | client.close(); 65 | } 66 | }; 67 | }; 68 | 69 | DownloadProgressClient.prototype.statStream = function statStream(requestMessage, metadata) { 70 | var listeners = { 71 | data: [], 72 | end: [], 73 | status: [] 74 | }; 75 | var client = grpc.invoke(DownloadProgress.StatStream, { 76 | request: requestMessage, 77 | host: this.serviceHost, 78 | metadata: metadata, 79 | transport: this.options.transport, 80 | debug: this.options.debug, 81 | onMessage: function (responseMessage) { 82 | listeners.data.forEach(function (handler) { 83 | handler(responseMessage); 84 | }); 85 | }, 86 | onEnd: function (status, statusMessage, trailers) { 87 | listeners.status.forEach(function (handler) { 88 | handler({ code: status, details: statusMessage, metadata: trailers }); 89 | }); 90 | listeners.end.forEach(function (handler) { 91 | handler({ code: status, details: statusMessage, metadata: trailers }); 92 | }); 93 | listeners = null; 94 | } 95 | }); 96 | return { 97 | on: function (type, handler) { 98 | listeners[type].push(handler); 99 | return this; 100 | }, 101 | cancel: function () { 102 | listeners = null; 103 | client.close(); 104 | } 105 | }; 106 | }; 107 | 108 | exports.DownloadProgressClient = DownloadProgressClient; 109 | 110 | -------------------------------------------------------------------------------- /proto/torrent-web-seeder/torrent-web-seeder_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-web-seeder/torrent-web-seeder.proto 3 | 4 | import * as proto_torrent_web_seeder_torrent_web_seeder_pb from "../../proto/torrent-web-seeder/torrent-web-seeder_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type TorrentWebSeederStat = { 8 | readonly methodName: string; 9 | readonly service: typeof TorrentWebSeeder; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest; 13 | readonly responseType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply; 14 | }; 15 | 16 | type TorrentWebSeederStatStream = { 17 | readonly methodName: string; 18 | readonly service: typeof TorrentWebSeeder; 19 | readonly requestStream: false; 20 | readonly responseStream: true; 21 | readonly requestType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest; 22 | readonly responseType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply; 23 | }; 24 | 25 | type TorrentWebSeederFiles = { 26 | readonly methodName: string; 27 | readonly service: typeof TorrentWebSeeder; 28 | readonly requestStream: false; 29 | readonly responseStream: false; 30 | readonly requestType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.FilesRequest; 31 | readonly responseType: typeof proto_torrent_web_seeder_torrent_web_seeder_pb.FilesReply; 32 | }; 33 | 34 | export class TorrentWebSeeder { 35 | static readonly serviceName: string; 36 | static readonly Stat: TorrentWebSeederStat; 37 | static readonly StatStream: TorrentWebSeederStatStream; 38 | static readonly Files: TorrentWebSeederFiles; 39 | } 40 | 41 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 42 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 43 | 44 | interface UnaryResponse { 45 | cancel(): void; 46 | } 47 | interface ResponseStream { 48 | cancel(): void; 49 | on(type: 'data', handler: (message: T) => void): ResponseStream; 50 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 51 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 52 | } 53 | interface RequestStream { 54 | write(message: T): RequestStream; 55 | end(): void; 56 | cancel(): void; 57 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 58 | on(type: 'status', handler: (status: Status) => void): RequestStream; 59 | } 60 | interface BidirectionalStream { 61 | write(message: ReqT): BidirectionalStream; 62 | end(): void; 63 | cancel(): void; 64 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 65 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 66 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 67 | } 68 | 69 | export class TorrentWebSeederClient { 70 | readonly serviceHost: string; 71 | 72 | constructor(serviceHost: string, options?: grpc.RpcOptions); 73 | stat( 74 | requestMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest, 75 | metadata: grpc.Metadata, 76 | callback: (error: ServiceError|null, responseMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply|null) => void 77 | ): UnaryResponse; 78 | stat( 79 | requestMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest, 80 | callback: (error: ServiceError|null, responseMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply|null) => void 81 | ): UnaryResponse; 82 | statStream(requestMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest, metadata?: grpc.Metadata): ResponseStream; 83 | files( 84 | requestMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesRequest, 85 | metadata: grpc.Metadata, 86 | callback: (error: ServiceError|null, responseMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesReply|null) => void 87 | ): UnaryResponse; 88 | files( 89 | requestMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesRequest, 90 | callback: (error: ServiceError|null, responseMessage: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesReply|null) => void 91 | ): UnaryResponse; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /proto/torrent-store/torrent-store_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-store/torrent-store.proto 3 | 4 | var proto_torrent_store_torrent_store_pb = require("../../proto/torrent-store/torrent-store_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var TorrentStore = (function () { 8 | function TorrentStore() {} 9 | TorrentStore.serviceName = "TorrentStore"; 10 | return TorrentStore; 11 | }()); 12 | 13 | TorrentStore.Push = { 14 | methodName: "Push", 15 | service: TorrentStore, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_torrent_store_torrent_store_pb.PushRequest, 19 | responseType: proto_torrent_store_torrent_store_pb.PushReply 20 | }; 21 | 22 | TorrentStore.Pull = { 23 | methodName: "Pull", 24 | service: TorrentStore, 25 | requestStream: false, 26 | responseStream: false, 27 | requestType: proto_torrent_store_torrent_store_pb.PullRequest, 28 | responseType: proto_torrent_store_torrent_store_pb.PullReply 29 | }; 30 | 31 | TorrentStore.Touch = { 32 | methodName: "Touch", 33 | service: TorrentStore, 34 | requestStream: false, 35 | responseStream: false, 36 | requestType: proto_torrent_store_torrent_store_pb.TouchRequest, 37 | responseType: proto_torrent_store_torrent_store_pb.TouchReply 38 | }; 39 | 40 | exports.TorrentStore = TorrentStore; 41 | 42 | function TorrentStoreClient(serviceHost, options) { 43 | this.serviceHost = serviceHost; 44 | this.options = options || {}; 45 | } 46 | 47 | TorrentStoreClient.prototype.push = function push(requestMessage, metadata, callback) { 48 | if (arguments.length === 2) { 49 | callback = arguments[1]; 50 | } 51 | var client = grpc.unary(TorrentStore.Push, { 52 | request: requestMessage, 53 | host: this.serviceHost, 54 | metadata: metadata, 55 | transport: this.options.transport, 56 | debug: this.options.debug, 57 | onEnd: function (response) { 58 | if (callback) { 59 | if (response.status !== grpc.Code.OK) { 60 | var err = new Error(response.statusMessage); 61 | err.code = response.status; 62 | err.metadata = response.trailers; 63 | callback(err, null); 64 | } else { 65 | callback(null, response.message); 66 | } 67 | } 68 | } 69 | }); 70 | return { 71 | cancel: function () { 72 | callback = null; 73 | client.close(); 74 | } 75 | }; 76 | }; 77 | 78 | TorrentStoreClient.prototype.pull = function pull(requestMessage, metadata, callback) { 79 | if (arguments.length === 2) { 80 | callback = arguments[1]; 81 | } 82 | var client = grpc.unary(TorrentStore.Pull, { 83 | request: requestMessage, 84 | host: this.serviceHost, 85 | metadata: metadata, 86 | transport: this.options.transport, 87 | debug: this.options.debug, 88 | onEnd: function (response) { 89 | if (callback) { 90 | if (response.status !== grpc.Code.OK) { 91 | var err = new Error(response.statusMessage); 92 | err.code = response.status; 93 | err.metadata = response.trailers; 94 | callback(err, null); 95 | } else { 96 | callback(null, response.message); 97 | } 98 | } 99 | } 100 | }); 101 | return { 102 | cancel: function () { 103 | callback = null; 104 | client.close(); 105 | } 106 | }; 107 | }; 108 | 109 | TorrentStoreClient.prototype.touch = function touch(requestMessage, metadata, callback) { 110 | if (arguments.length === 2) { 111 | callback = arguments[1]; 112 | } 113 | var client = grpc.unary(TorrentStore.Touch, { 114 | request: requestMessage, 115 | host: this.serviceHost, 116 | metadata: metadata, 117 | transport: this.options.transport, 118 | debug: this.options.debug, 119 | onEnd: function (response) { 120 | if (callback) { 121 | if (response.status !== grpc.Code.OK) { 122 | var err = new Error(response.statusMessage); 123 | err.code = response.status; 124 | err.metadata = response.trailers; 125 | callback(err, null); 126 | } else { 127 | callback(null, response.message); 128 | } 129 | } 130 | } 131 | }); 132 | return { 133 | cancel: function () { 134 | callback = null; 135 | client.close(); 136 | } 137 | }; 138 | }; 139 | 140 | exports.TorrentStoreClient = TorrentStoreClient; 141 | 142 | -------------------------------------------------------------------------------- /proto/torrent-store/torrent-store_pb_service.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-store/torrent-store.proto 3 | 4 | import * as proto_torrent_store_torrent_store_pb from "../../proto/torrent-store/torrent-store_pb"; 5 | import {grpc} from "@improbable-eng/grpc-web"; 6 | 7 | type TorrentStorePush = { 8 | readonly methodName: string; 9 | readonly service: typeof TorrentStore; 10 | readonly requestStream: false; 11 | readonly responseStream: false; 12 | readonly requestType: typeof proto_torrent_store_torrent_store_pb.PushRequest; 13 | readonly responseType: typeof proto_torrent_store_torrent_store_pb.PushReply; 14 | }; 15 | 16 | type TorrentStorePull = { 17 | readonly methodName: string; 18 | readonly service: typeof TorrentStore; 19 | readonly requestStream: false; 20 | readonly responseStream: false; 21 | readonly requestType: typeof proto_torrent_store_torrent_store_pb.PullRequest; 22 | readonly responseType: typeof proto_torrent_store_torrent_store_pb.PullReply; 23 | }; 24 | 25 | type TorrentStoreTouch = { 26 | readonly methodName: string; 27 | readonly service: typeof TorrentStore; 28 | readonly requestStream: false; 29 | readonly responseStream: false; 30 | readonly requestType: typeof proto_torrent_store_torrent_store_pb.TouchRequest; 31 | readonly responseType: typeof proto_torrent_store_torrent_store_pb.TouchReply; 32 | }; 33 | 34 | export class TorrentStore { 35 | static readonly serviceName: string; 36 | static readonly Push: TorrentStorePush; 37 | static readonly Pull: TorrentStorePull; 38 | static readonly Touch: TorrentStoreTouch; 39 | } 40 | 41 | export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } 42 | export type Status = { details: string, code: number; metadata: grpc.Metadata } 43 | 44 | interface UnaryResponse { 45 | cancel(): void; 46 | } 47 | interface ResponseStream { 48 | cancel(): void; 49 | on(type: 'data', handler: (message: T) => void): ResponseStream; 50 | on(type: 'end', handler: (status?: Status) => void): ResponseStream; 51 | on(type: 'status', handler: (status: Status) => void): ResponseStream; 52 | } 53 | interface RequestStream { 54 | write(message: T): RequestStream; 55 | end(): void; 56 | cancel(): void; 57 | on(type: 'end', handler: (status?: Status) => void): RequestStream; 58 | on(type: 'status', handler: (status: Status) => void): RequestStream; 59 | } 60 | interface BidirectionalStream { 61 | write(message: ReqT): BidirectionalStream; 62 | end(): void; 63 | cancel(): void; 64 | on(type: 'data', handler: (message: ResT) => void): BidirectionalStream; 65 | on(type: 'end', handler: (status?: Status) => void): BidirectionalStream; 66 | on(type: 'status', handler: (status: Status) => void): BidirectionalStream; 67 | } 68 | 69 | export class TorrentStoreClient { 70 | readonly serviceHost: string; 71 | 72 | constructor(serviceHost: string, options?: grpc.RpcOptions); 73 | push( 74 | requestMessage: proto_torrent_store_torrent_store_pb.PushRequest, 75 | metadata: grpc.Metadata, 76 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.PushReply|null) => void 77 | ): UnaryResponse; 78 | push( 79 | requestMessage: proto_torrent_store_torrent_store_pb.PushRequest, 80 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.PushReply|null) => void 81 | ): UnaryResponse; 82 | pull( 83 | requestMessage: proto_torrent_store_torrent_store_pb.PullRequest, 84 | metadata: grpc.Metadata, 85 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.PullReply|null) => void 86 | ): UnaryResponse; 87 | pull( 88 | requestMessage: proto_torrent_store_torrent_store_pb.PullRequest, 89 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.PullReply|null) => void 90 | ): UnaryResponse; 91 | touch( 92 | requestMessage: proto_torrent_store_torrent_store_pb.TouchRequest, 93 | metadata: grpc.Metadata, 94 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.TouchReply|null) => void 95 | ): UnaryResponse; 96 | touch( 97 | requestMessage: proto_torrent_store_torrent_store_pb.TouchRequest, 98 | callback: (error: ServiceError|null, responseMessage: proto_torrent_store_torrent_store_pb.TouchReply|null) => void 99 | ): UnaryResponse; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /proto/torrent-web-seeder/torrent-web-seeder_pb_service.js: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-web-seeder/torrent-web-seeder.proto 3 | 4 | var proto_torrent_web_seeder_torrent_web_seeder_pb = require("../../proto/torrent-web-seeder/torrent-web-seeder_pb"); 5 | var grpc = require("@improbable-eng/grpc-web").grpc; 6 | 7 | var TorrentWebSeeder = (function () { 8 | function TorrentWebSeeder() {} 9 | TorrentWebSeeder.serviceName = "TorrentWebSeeder"; 10 | return TorrentWebSeeder; 11 | }()); 12 | 13 | TorrentWebSeeder.Stat = { 14 | methodName: "Stat", 15 | service: TorrentWebSeeder, 16 | requestStream: false, 17 | responseStream: false, 18 | requestType: proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest, 19 | responseType: proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply 20 | }; 21 | 22 | TorrentWebSeeder.StatStream = { 23 | methodName: "StatStream", 24 | service: TorrentWebSeeder, 25 | requestStream: false, 26 | responseStream: true, 27 | requestType: proto_torrent_web_seeder_torrent_web_seeder_pb.StatRequest, 28 | responseType: proto_torrent_web_seeder_torrent_web_seeder_pb.StatReply 29 | }; 30 | 31 | TorrentWebSeeder.Files = { 32 | methodName: "Files", 33 | service: TorrentWebSeeder, 34 | requestStream: false, 35 | responseStream: false, 36 | requestType: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesRequest, 37 | responseType: proto_torrent_web_seeder_torrent_web_seeder_pb.FilesReply 38 | }; 39 | 40 | exports.TorrentWebSeeder = TorrentWebSeeder; 41 | 42 | function TorrentWebSeederClient(serviceHost, options) { 43 | this.serviceHost = serviceHost; 44 | this.options = options || {}; 45 | } 46 | 47 | TorrentWebSeederClient.prototype.stat = function stat(requestMessage, metadata, callback) { 48 | if (arguments.length === 2) { 49 | callback = arguments[1]; 50 | } 51 | var client = grpc.unary(TorrentWebSeeder.Stat, { 52 | request: requestMessage, 53 | host: this.serviceHost, 54 | metadata: metadata, 55 | transport: this.options.transport, 56 | debug: this.options.debug, 57 | onEnd: function (response) { 58 | if (callback) { 59 | if (response.status !== grpc.Code.OK) { 60 | var err = new Error(response.statusMessage); 61 | err.code = response.status; 62 | err.metadata = response.trailers; 63 | callback(err, null); 64 | } else { 65 | callback(null, response.message); 66 | } 67 | } 68 | } 69 | }); 70 | return { 71 | cancel: function () { 72 | callback = null; 73 | client.close(); 74 | } 75 | }; 76 | }; 77 | 78 | TorrentWebSeederClient.prototype.statStream = function statStream(requestMessage, metadata) { 79 | var listeners = { 80 | data: [], 81 | end: [], 82 | status: [] 83 | }; 84 | var client = grpc.invoke(TorrentWebSeeder.StatStream, { 85 | request: requestMessage, 86 | host: this.serviceHost, 87 | metadata: metadata, 88 | transport: this.options.transport, 89 | debug: this.options.debug, 90 | onMessage: function (responseMessage) { 91 | listeners.data.forEach(function (handler) { 92 | handler(responseMessage); 93 | }); 94 | }, 95 | onEnd: function (status, statusMessage, trailers) { 96 | listeners.status.forEach(function (handler) { 97 | handler({ code: status, details: statusMessage, metadata: trailers }); 98 | }); 99 | listeners.end.forEach(function (handler) { 100 | handler({ code: status, details: statusMessage, metadata: trailers }); 101 | }); 102 | listeners = null; 103 | } 104 | }); 105 | return { 106 | on: function (type, handler) { 107 | listeners[type].push(handler); 108 | return this; 109 | }, 110 | cancel: function () { 111 | listeners = null; 112 | client.close(); 113 | } 114 | }; 115 | }; 116 | 117 | TorrentWebSeederClient.prototype.files = function files(requestMessage, metadata, callback) { 118 | if (arguments.length === 2) { 119 | callback = arguments[1]; 120 | } 121 | var client = grpc.unary(TorrentWebSeeder.Files, { 122 | request: requestMessage, 123 | host: this.serviceHost, 124 | metadata: metadata, 125 | transport: this.options.transport, 126 | debug: this.options.debug, 127 | onEnd: function (response) { 128 | if (callback) { 129 | if (response.status !== grpc.Code.OK) { 130 | var err = new Error(response.statusMessage); 131 | err.code = response.status; 132 | err.metadata = response.trailers; 133 | callback(err, null); 134 | } else { 135 | callback(null, response.message); 136 | } 137 | } 138 | } 139 | }); 140 | return { 141 | cancel: function () { 142 | callback = null; 143 | client.close(); 144 | } 145 | }; 146 | }; 147 | 148 | exports.TorrentWebSeederClient = TorrentWebSeederClient; 149 | 150 | -------------------------------------------------------------------------------- /proto/abuse-store/abuse-store_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/abuse-store/abuse-store.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class PushReply extends jspb.Message { 7 | serializeBinary(): Uint8Array; 8 | toObject(includeInstance?: boolean): PushReply.AsObject; 9 | static toObject(includeInstance: boolean, msg: PushReply): PushReply.AsObject; 10 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 11 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 12 | static serializeBinaryToWriter(message: PushReply, writer: jspb.BinaryWriter): void; 13 | static deserializeBinary(bytes: Uint8Array): PushReply; 14 | static deserializeBinaryFromReader(message: PushReply, reader: jspb.BinaryReader): PushReply; 15 | } 16 | 17 | export namespace PushReply { 18 | export type AsObject = { 19 | } 20 | } 21 | 22 | export class PushRequest extends jspb.Message { 23 | getNoticeId(): string; 24 | setNoticeId(value: string): void; 25 | 26 | getInfohash(): string; 27 | setInfohash(value: string): void; 28 | 29 | getFilename(): string; 30 | setFilename(value: string): void; 31 | 32 | getWork(): string; 33 | setWork(value: string): void; 34 | 35 | getStartedAt(): number; 36 | setStartedAt(value: number): void; 37 | 38 | getEmail(): string; 39 | setEmail(value: string): void; 40 | 41 | getDescription(): string; 42 | setDescription(value: string): void; 43 | 44 | getSubject(): string; 45 | setSubject(value: string): void; 46 | 47 | getCause(): PushRequest.CauseMap[keyof PushRequest.CauseMap]; 48 | setCause(value: PushRequest.CauseMap[keyof PushRequest.CauseMap]): void; 49 | 50 | getSource(): PushRequest.SourceMap[keyof PushRequest.SourceMap]; 51 | setSource(value: PushRequest.SourceMap[keyof PushRequest.SourceMap]): void; 52 | 53 | serializeBinary(): Uint8Array; 54 | toObject(includeInstance?: boolean): PushRequest.AsObject; 55 | static toObject(includeInstance: boolean, msg: PushRequest): PushRequest.AsObject; 56 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 57 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 58 | static serializeBinaryToWriter(message: PushRequest, writer: jspb.BinaryWriter): void; 59 | static deserializeBinary(bytes: Uint8Array): PushRequest; 60 | static deserializeBinaryFromReader(message: PushRequest, reader: jspb.BinaryReader): PushRequest; 61 | } 62 | 63 | export namespace PushRequest { 64 | export type AsObject = { 65 | noticeId: string, 66 | infohash: string, 67 | filename: string, 68 | work: string, 69 | startedAt: number, 70 | email: string, 71 | description: string, 72 | subject: string, 73 | cause: PushRequest.CauseMap[keyof PushRequest.CauseMap], 74 | source: PushRequest.SourceMap[keyof PushRequest.SourceMap], 75 | } 76 | 77 | export interface CauseMap { 78 | ILLEGAL_CONTENT: 0; 79 | MALWARE: 1; 80 | APP_ERROR: 2; 81 | QUESTION: 3; 82 | } 83 | 84 | export const Cause: CauseMap; 85 | 86 | export interface SourceMap { 87 | MAIL: 0; 88 | FORM: 1; 89 | } 90 | 91 | export const Source: SourceMap; 92 | } 93 | 94 | export class CheckRequest extends jspb.Message { 95 | getInfohash(): string; 96 | setInfohash(value: string): void; 97 | 98 | serializeBinary(): Uint8Array; 99 | toObject(includeInstance?: boolean): CheckRequest.AsObject; 100 | static toObject(includeInstance: boolean, msg: CheckRequest): CheckRequest.AsObject; 101 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 102 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 103 | static serializeBinaryToWriter(message: CheckRequest, writer: jspb.BinaryWriter): void; 104 | static deserializeBinary(bytes: Uint8Array): CheckRequest; 105 | static deserializeBinaryFromReader(message: CheckRequest, reader: jspb.BinaryReader): CheckRequest; 106 | } 107 | 108 | export namespace CheckRequest { 109 | export type AsObject = { 110 | infohash: string, 111 | } 112 | } 113 | 114 | export class CheckReply extends jspb.Message { 115 | getExists(): boolean; 116 | setExists(value: boolean): void; 117 | 118 | serializeBinary(): Uint8Array; 119 | toObject(includeInstance?: boolean): CheckReply.AsObject; 120 | static toObject(includeInstance: boolean, msg: CheckReply): CheckReply.AsObject; 121 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 122 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 123 | static serializeBinaryToWriter(message: CheckReply, writer: jspb.BinaryWriter): void; 124 | static deserializeBinary(bytes: Uint8Array): CheckReply; 125 | static deserializeBinaryFromReader(message: CheckReply, reader: jspb.BinaryReader): CheckReply; 126 | } 127 | 128 | export namespace CheckReply { 129 | export type AsObject = { 130 | exists: boolean, 131 | } 132 | } 133 | 134 | -------------------------------------------------------------------------------- /src/sdk/loader/torrent/resource.js: -------------------------------------------------------------------------------- 1 | import parseTorrent from 'parse-torrent'; 2 | class Content { 3 | constructor({path, name, type}, sdk, seeder) { 4 | this.path = path; 5 | this.name = name; 6 | this.type = type; 7 | this.sdk = sdk; 8 | this.seeder = seeder; 9 | } 10 | get isFile() { 11 | return this.type == 'file'; 12 | } 13 | get isDir() { 14 | return this.type == 'dir'; 15 | } 16 | get mediaType() { 17 | if (this.isDir) return null; 18 | return this.sdk.util.getMediaType(this.name); 19 | } 20 | async getMimeType() { 21 | if (this.isDir) return null; 22 | return this.sdk.util.getMimeType(await this.getStreamUrl()); 23 | } 24 | async deliveryType() { 25 | if (this.isDir) return null; 26 | return this.sdk.util.getDeliveryType(this.name); 27 | } 28 | async getStreamUrl() { 29 | if (this.isDir) return null; 30 | return await this.seeder.streamUrl(this.path); 31 | } 32 | async getSegmentUrl(s, c) { 33 | if (this.isDir) return null; 34 | return await this.seeder.segmentUrl(this.path, s, c); 35 | } 36 | } 37 | class File extends Content { 38 | constructor(i, sdk, seeder) { 39 | super({ 40 | path: '/' + i.path, 41 | name: i.name, 42 | type: 'file', 43 | }, sdk, seeder); 44 | this.length = i.length; 45 | } 46 | } 47 | class Dir extends Content { 48 | constructor(path, name, sdk, seeder) { 49 | super({ 50 | path, 51 | name, 52 | type: 'dir', 53 | }, sdk, seeder); 54 | this.content = {}; 55 | } 56 | } 57 | class Resource { 58 | type = 'torrent'; 59 | constructor(torrent, sdk, seeder) { 60 | this.id = torrent.infoHash; 61 | this.torrent = torrent; 62 | this.sdk = sdk; 63 | this.seeder = seeder; 64 | } 65 | get title() { 66 | return this.torrent.name; 67 | } 68 | get shortType() { 69 | return this.type.charAt(0); 70 | } 71 | get magnetUri() { 72 | return parseTorrent.toMagnetURI(this.torrent); 73 | } 74 | addBranch(tree, parts, file, path) { 75 | if (parts.length == 0) return new File(file, this.sdk, this.seeder); 76 | const part = parts.shift(); 77 | path.push(part); 78 | if (parts.length > 0) { 79 | if (tree[part] == undefined) { 80 | tree[part] = new Dir('/' + path.join('/'), part, this.sdk, this.seeder); 81 | } 82 | tree[part].content = this.addBranch(tree[part].content, parts, file, path); 83 | } else { 84 | tree[part] = new File(file, this.sdk, this.seeder); 85 | } 86 | return tree; 87 | } 88 | get tree() { 89 | let tree = {}; 90 | for (let file of this.torrent.files) { 91 | const pathParts = file.path.split('/'); 92 | tree = this.addBranch(tree, pathParts, file, []); 93 | } 94 | return tree; 95 | } 96 | get root() { 97 | return '/' + Object.keys(this.tree)[0]; 98 | } 99 | dirname(path) { 100 | path = path.replace(/^\//, '').replace(/\/$/, ''); 101 | path = path.split('/'); 102 | let tree = this.tree; 103 | let dir = []; 104 | while (true) { 105 | const p = path.shift(path); 106 | if (tree[p] && tree[p].isDir) { 107 | dir.push(p); 108 | tree = tree[p].content; 109 | } else { 110 | break; 111 | } 112 | } 113 | return '/' + dir.join('/'); 114 | } 115 | filename(path) { 116 | path = path.replace(/^\//, '').replace(/\/$/, ''); 117 | path = path.split('/'); 118 | let tree = this.tree; 119 | while (true) { 120 | const p = path.shift(path); 121 | if (tree[p]) { 122 | tree = tree[p]; 123 | } else { 124 | break; 125 | } 126 | } 127 | if (tree.isFile && tree.isFile) { 128 | return tree.name; 129 | } 130 | return null 131 | } 132 | ls(path) { 133 | path = path.replace(/^\//, '').replace(/\/$/, ''); 134 | if (!path) { 135 | path = []; 136 | } else { 137 | path = path.split('/'); 138 | } 139 | let c = this.tree; 140 | for (let p of path) { 141 | c = c[p].content; 142 | } 143 | let res = []; 144 | for (let i in c) { 145 | res.push(c[i]); 146 | } 147 | if (path.length > 1) { 148 | path.pop(); 149 | res.push(new Dir( 150 | path.join('/'), 151 | '..', 152 | )); 153 | } 154 | res = res.sort((a, b) => a.name.localeCompare(b.name)); 155 | return res; 156 | } 157 | } 158 | export default function newResource(torrent, sdk) { 159 | 160 | const seeder = sdk.seeder.get(torrent.infoHash); 161 | return new Resource(torrent, sdk, seeder); 162 | } -------------------------------------------------------------------------------- /src/sdk/torrent.js: -------------------------------------------------------------------------------- 1 | import {TorrentStore} from '../../proto/torrent-store/torrent-store_pb_service'; 2 | import {PullRequest, PushRequest, TouchRequest} from '../../proto/torrent-store/torrent-store_pb'; 3 | import {grpc} from '@improbable-eng/grpc-web'; 4 | import process from './process'; 5 | import parseTorrent from 'parse-torrent'; 6 | const debug = require('debug')('webtor:sdk:torrent'); 7 | 8 | export default function(params = {}) { 9 | const self = {params}; 10 | return { 11 | fromUrl(url) { 12 | debug('fetch torrent from url=%s', url); 13 | return new Promise((resolve, reject) => { 14 | const xhr = new XMLHttpRequest(); 15 | xhr.addEventListener('error', reject); 16 | xhr.onreadystatechange = async function() { 17 | if (this.readyState == XMLHttpRequest.DONE) { 18 | const ab = new Uint8Array(this.response); 19 | const buffer = new Buffer(ab.byteLength); 20 | const view = new Uint8Array(ab); 21 | for (let i = 0; i < buffer.length; ++i) { 22 | buffer[i] = view[i]; 23 | } 24 | resolve(parseTorrent(buffer)); 25 | } 26 | }; 27 | xhr.open('GET', url); 28 | xhr.responseType = 'arraybuffer'; 29 | xhr.send(); 30 | }); 31 | }, 32 | pull(infoHash, metadata = {}, params = {}) { 33 | params = Object.assign(self.params, params); 34 | const url = params.apiUrl + params.endpoints.torrent; 35 | debug('pull torrent infoHash=%s url=%s metadata=%o', infoHash, url, metadata); 36 | const request = new PullRequest(); 37 | request.setInfohash(infoHash); 38 | const client = () => grpc.client(TorrentStore.Pull, { 39 | host: url, 40 | // transport: grpc.WebsocketTransport(), 41 | debug: params.grpcDebug, 42 | }); 43 | const onMessage = (message, resolve, reject) => { 44 | if (message.torrent == '') { 45 | return reject('no torrent'); 46 | } 47 | let torrent = Buffer.from(message.torrent, 'base64'); 48 | torrent = parseTorrent(torrent); 49 | debug('and finally torrent=%o', torrent); 50 | resolve(torrent); 51 | } 52 | const onEnd = (res, resolve, reject) => { 53 | if (res == grpc.Code.PermissionDenied) { 54 | reject('abused'); 55 | } else if (res !== grpc.Code.OK) { 56 | reject('failed to pull torrent code=' + res); 57 | } 58 | } 59 | return process(client, request, onMessage, onEnd, metadata, params); 60 | }, 61 | push(torrent, expire, metadata = {}, params = {}) { 62 | params = Object.assign(self.params, params); 63 | const url = params.apiUrl + params.endpoints.torrent; 64 | debug('push torrent url=%s metadata=%o', url, metadata); 65 | const request = new PushRequest(); 66 | request.setTorrent(parseTorrent.toTorrentFile(torrent)); 67 | const client = () => grpc.client(TorrentStore.Push, { 68 | host: url, 69 | // transport: grpc.WebsocketTransport(), 70 | debug: params.grpcDebug, 71 | }); 72 | const onEnd = (res, resolve, reject) => { 73 | if (res === grpc.Code.OK) { 74 | debug('torrent stored'); 75 | resolve(); 76 | } else if (res === grpc.Code.NotFound) { 77 | reject('not found'); 78 | } else if (res === grpc.Code.PermissionDenied) { 79 | reject('abused'); 80 | } else { 81 | reject('failed to push torrent code=' + res); 82 | } 83 | 84 | } 85 | return process(client, request, null, onEnd, metadata, params); 86 | }, 87 | touch(torrent, expire, metadata = {}, params = {}) { 88 | params = Object.assign(self.params, params); 89 | const url = params.apiUrl + params.endpoints.torrent; 90 | debug('touch torrent url=%s metadata=%o', url, metadata); 91 | const request = new TouchRequest(); 92 | request.setInfohash(torrent.infoHash); 93 | const client = () => grpc.client(TorrentStore.Touch, { 94 | host: url, 95 | // transport: grpc.WebsocketTransport(), 96 | debug: params.grpcDebug, 97 | }); 98 | const onEnd = (res, resolve, reject) => { 99 | if (res === grpc.Code.OK) { 100 | debug('torrent touched'); 101 | resolve(); 102 | } else if (res === grpc.Code.PermissionDenied) { 103 | reject('abused'); 104 | } else if (res === grpc.Code.NotFound) { 105 | reject('not found'); 106 | } else { 107 | reject('failed to touch torrent code=' + res); 108 | } 109 | } 110 | return process(client, request, null, onEnd, metadata, params); 111 | }, 112 | }; 113 | } -------------------------------------------------------------------------------- /src/sdk/loader.js: -------------------------------------------------------------------------------- 1 | import parseTorrent from 'parse-torrent'; 2 | import newTorrentResource from './loader/torrent/resource'; 3 | const debug = require('debug')('webtor:sdk:loader'); 4 | export default function(params, sdk) { 5 | const self = {params, sdk}; 6 | return { 7 | async load(source, metadata, params = {}) { 8 | debug('loading source=%o', source); 9 | 10 | params = Object.assign(self.params, params); 11 | let torrent = false; 12 | if (torrent == false) torrent = await this.loadTorrentObject(source, metadata, params); 13 | if (torrent == false) torrent = await this.loadTorrentFile(source, metadata, params); 14 | if (torrent == false) torrent = await this.loadMagnet(source, metadata, params); 15 | if (torrent == false) torrent = await this.loadTorrentUrl(source, metadata, params); 16 | if (torrent != false) await this.pushTorrent(torrent, metadata, params); 17 | if (torrent == false) throw 'failed to load resource'; 18 | return newTorrentResource(torrent, sdk); 19 | }, 20 | async loadById(type, id, metadata, params = {}) { 21 | debug('loading type=%o id=%o', type, id); 22 | params = Object.assign(self.params, params); 23 | if (type == 'torrent' || type == 't') { 24 | let torrent = false; 25 | if (torrent == false) torrent = await this.loadMagnet(id, metadata, params); 26 | if (torrent != false) await this.pushTorrent(torrent, metadata, params); 27 | return newTorrentResource(torrent, sdk); 28 | } 29 | }, 30 | async pushTorrent(torrent, metadata, params = {}) { 31 | const expire = 60 * 60 * 24 * 30; // 1 month 32 | params = Object.assign(self.params, params); 33 | debug('push torrent infohash=%o', torrent.infoHash); 34 | try { 35 | return await sdk.torrent.touch(torrent, expire, metadata); 36 | } catch (e) { 37 | if (e == 'not found') { 38 | try { 39 | return await sdk.torrent.push(torrent, expire, metadata); 40 | } catch (e) { 41 | debug(e); 42 | throw e; 43 | } 44 | } else { 45 | debug(e); 46 | throw e; 47 | } 48 | } 49 | }, 50 | async loadTorrentObject(source, metadata, params = {}) { 51 | if (!(typeof source == 'object' && source.infoHash != undefined && source.files != undefined)) return false; 52 | return source; 53 | }, 54 | async loadTorrentUrl(source, metadata, params = {}) { 55 | if (!source.match(/^http/)) return false; 56 | if (!source.match(/\.torrent$/) && !source.match(/[a-fA-F0-9]{40}/)) { 57 | return false; 58 | } 59 | source = await sdk.ext.url(source); 60 | return await new Promise((resolve, reject) => { 61 | const xhr = new XMLHttpRequest(); 62 | xhr.addEventListener('error', reject); 63 | xhr.onreadystatechange = async function() { 64 | if (this.readyState == XMLHttpRequest.DONE) { 65 | const ab = new Uint8Array(this.response); 66 | const buffer = new Buffer(ab.byteLength); 67 | const view = new Uint8Array(ab); 68 | for (let i = 0; i < buffer.length; ++i) { 69 | buffer[i] = view[i]; 70 | } 71 | resolve(parseTorrent(buffer)); 72 | } 73 | }; 74 | xhr.open('GET', source); 75 | xhr.responseType = 'arraybuffer'; 76 | xhr.send(); 77 | }); 78 | }, 79 | async loadTorrentFile(source, metadata, params = {}) { 80 | if (!(typeof source == 'object' && source.type == 'application/x-bittorrent' && source.size)) return false; 81 | try { 82 | const b = await this.fileToArray(source); 83 | return parseTorrent(b); 84 | } catch (e) { 85 | debug(e); 86 | throw e; 87 | } 88 | }, 89 | async loadMagnet(source, metadata, params = {}) { 90 | params = Object.assign(self.params, params); 91 | let torrent = null; 92 | if (!source.match(/^magnet/) && !source.match(/^[a-fA-F0-9]{40}$/)) { 93 | return false; 94 | } 95 | try { 96 | torrent = parseTorrent(source); 97 | } catch (e) { 98 | debug(e); 99 | throw e; 100 | } 101 | const infoHash = torrent.infoHash; 102 | if (infoHash && params.db) { 103 | debug('loading from local db infohash=%o', infoHash) 104 | torrent = await params.db.pullTorrent(infoHash); 105 | } 106 | if (!torrent || !torrent.pieces || torrent.pieces.length == 0) { 107 | try { 108 | debug('loading from torrent store infohash=%o', infoHash) 109 | torrent = await sdk.torrent.pull(infoHash, metadata); 110 | } catch (e) { 111 | debug(e); 112 | throw e; 113 | } 114 | } 115 | if (!torrent) { 116 | debug('loading by magnet uri from peers magnet=%o', source); 117 | torrent = await sdk.magnet.fetchTorrent(source, metadata); 118 | } 119 | return torrent; 120 | }, 121 | fileToArray(file) { 122 | return new Promise((resolve, reject) => { 123 | const reader = new FileReader(); 124 | reader.addEventListener('load', (e) => { 125 | const arr = new Uint8Array(e.target.result); 126 | const buffer = new Buffer(arr); 127 | try { 128 | resolve(buffer); 129 | } catch(e) { 130 | reject(e); 131 | } 132 | }); 133 | reader.addEventListener('error', (err) => { 134 | reject(err); 135 | }); 136 | reader.readAsArrayBuffer(file); 137 | }); 138 | } 139 | }; 140 | }; -------------------------------------------------------------------------------- /proto/torrent-web-seeder/torrent-web-seeder_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-web-seeder/torrent-web-seeder.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class StatRequest extends jspb.Message { 7 | getPath(): string; 8 | setPath(value: string): void; 9 | 10 | serializeBinary(): Uint8Array; 11 | toObject(includeInstance?: boolean): StatRequest.AsObject; 12 | static toObject(includeInstance: boolean, msg: StatRequest): StatRequest.AsObject; 13 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 14 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 15 | static serializeBinaryToWriter(message: StatRequest, writer: jspb.BinaryWriter): void; 16 | static deserializeBinary(bytes: Uint8Array): StatRequest; 17 | static deserializeBinaryFromReader(message: StatRequest, reader: jspb.BinaryReader): StatRequest; 18 | } 19 | 20 | export namespace StatRequest { 21 | export type AsObject = { 22 | path: string, 23 | } 24 | } 25 | 26 | export class StatReply extends jspb.Message { 27 | getTotal(): number; 28 | setTotal(value: number): void; 29 | 30 | getCompleted(): number; 31 | setCompleted(value: number): void; 32 | 33 | getPeers(): number; 34 | setPeers(value: number): void; 35 | 36 | getStatus(): StatReply.StatusMap[keyof StatReply.StatusMap]; 37 | setStatus(value: StatReply.StatusMap[keyof StatReply.StatusMap]): void; 38 | 39 | clearPiecesList(): void; 40 | getPiecesList(): Array; 41 | setPiecesList(value: Array): void; 42 | addPieces(value?: Piece, index?: number): Piece; 43 | 44 | getSeeders(): number; 45 | setSeeders(value: number): void; 46 | 47 | getLeechers(): number; 48 | setLeechers(value: number): void; 49 | 50 | serializeBinary(): Uint8Array; 51 | toObject(includeInstance?: boolean): StatReply.AsObject; 52 | static toObject(includeInstance: boolean, msg: StatReply): StatReply.AsObject; 53 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 54 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 55 | static serializeBinaryToWriter(message: StatReply, writer: jspb.BinaryWriter): void; 56 | static deserializeBinary(bytes: Uint8Array): StatReply; 57 | static deserializeBinaryFromReader(message: StatReply, reader: jspb.BinaryReader): StatReply; 58 | } 59 | 60 | export namespace StatReply { 61 | export type AsObject = { 62 | total: number, 63 | completed: number, 64 | peers: number, 65 | status: StatReply.StatusMap[keyof StatReply.StatusMap], 66 | piecesList: Array, 67 | seeders: number, 68 | leechers: number, 69 | } 70 | 71 | export interface StatusMap { 72 | INITIALIZATION: 0; 73 | SEEDING: 1; 74 | IDLE: 2; 75 | TERMINATED: 3; 76 | WAITING_FOR_PEERS: 4; 77 | RESTORING: 5; 78 | BACKINGUP: 6; 79 | } 80 | 81 | export const Status: StatusMap; 82 | } 83 | 84 | export class Piece extends jspb.Message { 85 | getPosition(): number; 86 | setPosition(value: number): void; 87 | 88 | getComplete(): boolean; 89 | setComplete(value: boolean): void; 90 | 91 | getPriority(): Piece.PriorityMap[keyof Piece.PriorityMap]; 92 | setPriority(value: Piece.PriorityMap[keyof Piece.PriorityMap]): void; 93 | 94 | serializeBinary(): Uint8Array; 95 | toObject(includeInstance?: boolean): Piece.AsObject; 96 | static toObject(includeInstance: boolean, msg: Piece): Piece.AsObject; 97 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 98 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 99 | static serializeBinaryToWriter(message: Piece, writer: jspb.BinaryWriter): void; 100 | static deserializeBinary(bytes: Uint8Array): Piece; 101 | static deserializeBinaryFromReader(message: Piece, reader: jspb.BinaryReader): Piece; 102 | } 103 | 104 | export namespace Piece { 105 | export type AsObject = { 106 | position: number, 107 | complete: boolean, 108 | priority: Piece.PriorityMap[keyof Piece.PriorityMap], 109 | } 110 | 111 | export interface PriorityMap { 112 | NONE: 0; 113 | NORMAL: 1; 114 | HIGH: 2; 115 | READAHEAD: 3; 116 | NEXT: 4; 117 | NOW: 5; 118 | } 119 | 120 | export const Priority: PriorityMap; 121 | } 122 | 123 | export class FilesRequest extends jspb.Message { 124 | serializeBinary(): Uint8Array; 125 | toObject(includeInstance?: boolean): FilesRequest.AsObject; 126 | static toObject(includeInstance: boolean, msg: FilesRequest): FilesRequest.AsObject; 127 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 128 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 129 | static serializeBinaryToWriter(message: FilesRequest, writer: jspb.BinaryWriter): void; 130 | static deserializeBinary(bytes: Uint8Array): FilesRequest; 131 | static deserializeBinaryFromReader(message: FilesRequest, reader: jspb.BinaryReader): FilesRequest; 132 | } 133 | 134 | export namespace FilesRequest { 135 | export type AsObject = { 136 | } 137 | } 138 | 139 | export class File extends jspb.Message { 140 | getPath(): string; 141 | setPath(value: string): void; 142 | 143 | serializeBinary(): Uint8Array; 144 | toObject(includeInstance?: boolean): File.AsObject; 145 | static toObject(includeInstance: boolean, msg: File): File.AsObject; 146 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 147 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 148 | static serializeBinaryToWriter(message: File, writer: jspb.BinaryWriter): void; 149 | static deserializeBinary(bytes: Uint8Array): File; 150 | static deserializeBinaryFromReader(message: File, reader: jspb.BinaryReader): File; 151 | } 152 | 153 | export namespace File { 154 | export type AsObject = { 155 | path: string, 156 | } 157 | } 158 | 159 | export class FilesReply extends jspb.Message { 160 | clearFilesList(): void; 161 | getFilesList(): Array; 162 | setFilesList(value: Array): void; 163 | addFiles(value?: File, index?: number): File; 164 | 165 | serializeBinary(): Uint8Array; 166 | toObject(includeInstance?: boolean): FilesReply.AsObject; 167 | static toObject(includeInstance: boolean, msg: FilesReply): FilesReply.AsObject; 168 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 169 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 170 | static serializeBinaryToWriter(message: FilesReply, writer: jspb.BinaryWriter): void; 171 | static deserializeBinary(bytes: Uint8Array): FilesReply; 172 | static deserializeBinaryFromReader(message: FilesReply, reader: jspb.BinaryReader): FilesReply; 173 | } 174 | 175 | export namespace FilesReply { 176 | export type AsObject = { 177 | filesList: Array, 178 | } 179 | } 180 | 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ [ARCHIVED] Webtor Platform SDK (JS) 2 | 3 | This repository is now **archived** and no longer maintained. 4 | For continued development and self-hosted solutions, please refer to the **new repository**: 5 | 6 | 👉 **[Webtor.io Self-Hosted](https://github.com/webtor-io/self-hosted)** 7 | 8 | ## ❓ What This Means 9 | - No further updates or maintenance will be provided for this repository. 10 | - We recommend **migrating** to the **self-hosted** Webtor.io solution. 11 | - Issues and feature requests will no longer be addressed here. 12 | 13 | ## 🔗 Migration Guide 14 | To set up and use Webtor.io in a self-hosted environment, visit: 15 | 📌 **[Webtor.io Self-Hosted Documentation](https://github.com/webtor-io/self-hosted)** 16 | 17 | --- 18 | 19 | Thank you for your support and contributions! 🚀 20 | 21 | ## Features 22 | 1. Online torrent content streaming without waiting for full download 23 | 2. On-the-fly content transcoding 24 | 3. Downloading torrent as ZIP-archive 25 | 4. Subtitle transcoding, srt to vtt 26 | 5. OpenSubtitles support 27 | 6. Streaming of external resources (including transcoding) 28 | 29 | ## Supported formats 30 | * Video: avi, mkv, mp4, webm, m4v 31 | * Audio: mp3, wav, ogg, flac, m4a 32 | * Images: png, gif, jpg, jpeg 33 | * Subtitles: srt, vtt 34 | 35 | ## Prerequisites 36 | Before moving further we must be sure that webtor backend api is already installed. 37 | Just follow [this guide](https://github.com/webtor-io/helm-charts) to setup all the things. 38 | 39 | ## Installation 40 | ```bash 41 | npm install @webtor/platform-sdk-js 42 | ``` 43 | or 44 | ```bash 45 | yarn add @webtor/platform-sdk-js 46 | ``` 47 | 48 | ## Basic usage 49 | Just a simple example of fetching torrent by magnet-uri, getting streaming url and stats: 50 | ```js 51 | import webtor from '@webtor/platform-sdk-js'; 52 | 53 | const sdk = webtor({ 54 | apiUrl: '...', 55 | }); 56 | 57 | const magnetUri = '...'; 58 | 59 | const torrent = await sdk.magnet.fetchTorrent(magnetUri); 60 | 61 | const expire = 60*60*24; 62 | 63 | await sdk.torrent.push(torrent, expire); 64 | 65 | const seeder = sdk.seeder.get(torrent.infoHash); 66 | 67 | const filePath = torrent.files[0].path; 68 | 69 | const url = await seeder.streamUrl(filePath); 70 | console.log(url); 71 | 72 | // NOTE: stats will become available only after content url access 73 | seeder.stats(filePath, (path, data) => { 74 | console.log(data); 75 | }); 76 | ``` 77 | You can find fully working example [here](https://github.com/webtor-io/platform-sdk-js/tree/master/example)! 78 | 79 | ## Initialization 80 | 81 | ### `const sdk = webtor(options)` 82 | 83 | `options` should be the following: 84 | 85 | ``` 86 | { 87 | apiUrl: String, // API url (required) 88 | apiKey: String, // API key 89 | downloadUrl: String, // All download urls will contain this location 90 | tokenUrl: String, // API will get access-token from this location 91 | tokenRenewInterval: Number, // Renews access-token after specific period in ms 92 | grpcDebug: Boolean, // If enabled shows grpc-web debug output 93 | statsRetryInterval: Number, // If stats not available for this file it will retry after specific period in ms (default=3000) 94 | getToken: function() Promise // If defined custom token-function will be used 95 | } 96 | ``` 97 | 98 | ## sdk.torrent 99 | Provides functions for storing and retriving torrent-files. 100 | 101 | ### `sdk.torrent.fromUrl(url)` 102 | Fetches parsed torrent from specific url. Be sure that appropriate CORS-headers are set on server-side in case of cross-site request (`Access-Control-Allow-Origin: *`). 103 | 104 | ### `sdk.torrent.pull(infoHash)` 105 | Pulls parsed torrent by infoHash from torrent-store. 106 | 107 | ### `sdk.torrent.push(torrent, expire)` 108 | Pushes parsed torrent to torrent-store with specific expiration time in seconds. We can use any parsed torrent generated by [parse-torrent](https://github.com/webtorrent/parse-torrent) there. 109 | 110 | ### `sdk.torrent.touch(torrent, expire)` 111 | Just renews expiration date of torrent-file. 112 | 113 | ## sdk.magnet 114 | Provides functions for working with magnet-urls. 115 | 116 | ### `sdk.magnet.fetchTorrent(magnet)` 117 | Fetches parsed torrent by magnet-uri. 118 | 119 | ## sdk.seeder 120 | Provides functions for retriving and streaming torrent-content. 121 | 122 | ### `const seeder = sdk.seeder.get(infoHash)` 123 | Returns seeder instance for the specific torrent stored in torrent-store. 124 | 125 | ### `seeder.url(path)` 126 | Returns `url` for original source file. 127 | 128 | ### `seeder.streamUrl(path, viewSettings = {})` 129 | Returns url capable for web-streaming. 130 | `viewSettings` should be provided only in case of content trnascoding. 131 | Possible `viewSettings`: 132 | ``` 133 | { 134 | a: Number, // Selected audio channel 135 | s: Number, // Selected subtitle channel 136 | } 137 | ``` 138 | 139 | ### `seeder.streamSubtitleUrl(path, viewSettings = {})` 140 | Returns subtitle-url capable for web-streaming. Can be used only for hls-transcoded content. 141 | `viewSettings` should be provided only in case of content trnascoding. 142 | Possible `viewSettings`: 143 | ``` 144 | { 145 | a: Number, // Selected audio channel 146 | s: Number, // Selected subtitle channel 147 | } 148 | ``` 149 | 150 | ### `seeder.mediaInfo(path)` 151 | Returns FFmpeg probing data. If content should not be transcoded only empty object `{}` will be returned. 152 | 153 | ### `seeder.downloadUrl(path)` 154 | Returns download url. 155 | 156 | ### `seeder.zipUrl(path)` 157 | Returns download url of zip-archive. Generates zip-archive of all files under directory and subdirectories specified by the `path`. 158 | 159 | ### `seeder.openSubtitles(path)` 160 | Returns object that includes all subtitles from [OpenSubtitles.org](https://opensubtitles.org). Automatically generates streaming urls for every subtitle (srt => vtt encoding). 161 | 162 | ### `const statClient = seeder.stats(path, function(path, data) { ... })` 163 | Receives status of specific file. Possible data: 164 | ``` 165 | { 166 | total: Number // Number of total bytes 167 | completed: Number // Number of completed bytes 168 | peers: Number // Total number of peers 169 | piecesList: [] // Array of pieces 170 | } 171 | ``` 172 | Also returns instance of stat client. 173 | 174 | ### `statClient.close()` 175 | Closes stat client 176 | 177 | ## sdk.ext 178 | Provides functions for retriving and streaming external resources. 179 | 180 | ### `sdk.ext.url(url)` 181 | Returns `url` for original external file proxied by the api. Can resolve CORS-issues. 182 | 183 | ### `sdk.ext.streamUrl(url, viewSettings = {})` 184 | Same as [`seeder.streamUrl`](#seeder-stream-url) but for external resource. 185 | 186 | ### `sdk.ext.streamSubtitleUrl(url, viewSettings = {})` 187 | Same as [`seeder.streamSubtitleUrl`](#seeder-stream-subtitle-url) but for external resource. 188 | 189 | ### `sdk.ext.mediaInfo(url)` 190 | Same as [`seeder.mediaInfo`](#seeder-media-info) but for external resource. 191 | 192 | ### `sdk.ext.openSubtitles(url)` 193 | Same as [`seeder.openSubtitles`](#seeder-opensubtitles) but for external resource. 194 | -------------------------------------------------------------------------------- /proto/torrent-store/torrent-store_pb.d.ts: -------------------------------------------------------------------------------- 1 | // package: 2 | // file: proto/torrent-store/torrent-store.proto 3 | 4 | import * as jspb from "google-protobuf"; 5 | 6 | export class PushReply extends jspb.Message { 7 | getInfohash(): string; 8 | setInfohash(value: string): void; 9 | 10 | serializeBinary(): Uint8Array; 11 | toObject(includeInstance?: boolean): PushReply.AsObject; 12 | static toObject(includeInstance: boolean, msg: PushReply): PushReply.AsObject; 13 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 14 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 15 | static serializeBinaryToWriter(message: PushReply, writer: jspb.BinaryWriter): void; 16 | static deserializeBinary(bytes: Uint8Array): PushReply; 17 | static deserializeBinaryFromReader(message: PushReply, reader: jspb.BinaryReader): PushReply; 18 | } 19 | 20 | export namespace PushReply { 21 | export type AsObject = { 22 | infohash: string, 23 | } 24 | } 25 | 26 | export class PushRequest extends jspb.Message { 27 | getTorrent(): Uint8Array | string; 28 | getTorrent_asU8(): Uint8Array; 29 | getTorrent_asB64(): string; 30 | setTorrent(value: Uint8Array | string): void; 31 | 32 | getExpire(): number; 33 | setExpire(value: number): void; 34 | 35 | serializeBinary(): Uint8Array; 36 | toObject(includeInstance?: boolean): PushRequest.AsObject; 37 | static toObject(includeInstance: boolean, msg: PushRequest): PushRequest.AsObject; 38 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 39 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 40 | static serializeBinaryToWriter(message: PushRequest, writer: jspb.BinaryWriter): void; 41 | static deserializeBinary(bytes: Uint8Array): PushRequest; 42 | static deserializeBinaryFromReader(message: PushRequest, reader: jspb.BinaryReader): PushRequest; 43 | } 44 | 45 | export namespace PushRequest { 46 | export type AsObject = { 47 | torrent: Uint8Array | string, 48 | expire: number, 49 | } 50 | } 51 | 52 | export class PullRequest extends jspb.Message { 53 | getInfohash(): string; 54 | setInfohash(value: string): void; 55 | 56 | serializeBinary(): Uint8Array; 57 | toObject(includeInstance?: boolean): PullRequest.AsObject; 58 | static toObject(includeInstance: boolean, msg: PullRequest): PullRequest.AsObject; 59 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 60 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 61 | static serializeBinaryToWriter(message: PullRequest, writer: jspb.BinaryWriter): void; 62 | static deserializeBinary(bytes: Uint8Array): PullRequest; 63 | static deserializeBinaryFromReader(message: PullRequest, reader: jspb.BinaryReader): PullRequest; 64 | } 65 | 66 | export namespace PullRequest { 67 | export type AsObject = { 68 | infohash: string, 69 | } 70 | } 71 | 72 | export class PullReply extends jspb.Message { 73 | getTorrent(): Uint8Array | string; 74 | getTorrent_asU8(): Uint8Array; 75 | getTorrent_asB64(): string; 76 | setTorrent(value: Uint8Array | string): void; 77 | 78 | serializeBinary(): Uint8Array; 79 | toObject(includeInstance?: boolean): PullReply.AsObject; 80 | static toObject(includeInstance: boolean, msg: PullReply): PullReply.AsObject; 81 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 82 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 83 | static serializeBinaryToWriter(message: PullReply, writer: jspb.BinaryWriter): void; 84 | static deserializeBinary(bytes: Uint8Array): PullReply; 85 | static deserializeBinaryFromReader(message: PullReply, reader: jspb.BinaryReader): PullReply; 86 | } 87 | 88 | export namespace PullReply { 89 | export type AsObject = { 90 | torrent: Uint8Array | string, 91 | } 92 | } 93 | 94 | export class CheckRequest extends jspb.Message { 95 | getInfohash(): string; 96 | setInfohash(value: string): void; 97 | 98 | serializeBinary(): Uint8Array; 99 | toObject(includeInstance?: boolean): CheckRequest.AsObject; 100 | static toObject(includeInstance: boolean, msg: CheckRequest): CheckRequest.AsObject; 101 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 102 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 103 | static serializeBinaryToWriter(message: CheckRequest, writer: jspb.BinaryWriter): void; 104 | static deserializeBinary(bytes: Uint8Array): CheckRequest; 105 | static deserializeBinaryFromReader(message: CheckRequest, reader: jspb.BinaryReader): CheckRequest; 106 | } 107 | 108 | export namespace CheckRequest { 109 | export type AsObject = { 110 | infohash: string, 111 | } 112 | } 113 | 114 | export class CheckReply extends jspb.Message { 115 | getExists(): boolean; 116 | setExists(value: boolean): void; 117 | 118 | serializeBinary(): Uint8Array; 119 | toObject(includeInstance?: boolean): CheckReply.AsObject; 120 | static toObject(includeInstance: boolean, msg: CheckReply): CheckReply.AsObject; 121 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 122 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 123 | static serializeBinaryToWriter(message: CheckReply, writer: jspb.BinaryWriter): void; 124 | static deserializeBinary(bytes: Uint8Array): CheckReply; 125 | static deserializeBinaryFromReader(message: CheckReply, reader: jspb.BinaryReader): CheckReply; 126 | } 127 | 128 | export namespace CheckReply { 129 | export type AsObject = { 130 | exists: boolean, 131 | } 132 | } 133 | 134 | export class TouchReply extends jspb.Message { 135 | serializeBinary(): Uint8Array; 136 | toObject(includeInstance?: boolean): TouchReply.AsObject; 137 | static toObject(includeInstance: boolean, msg: TouchReply): TouchReply.AsObject; 138 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 139 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 140 | static serializeBinaryToWriter(message: TouchReply, writer: jspb.BinaryWriter): void; 141 | static deserializeBinary(bytes: Uint8Array): TouchReply; 142 | static deserializeBinaryFromReader(message: TouchReply, reader: jspb.BinaryReader): TouchReply; 143 | } 144 | 145 | export namespace TouchReply { 146 | export type AsObject = { 147 | } 148 | } 149 | 150 | export class TouchRequest extends jspb.Message { 151 | getInfohash(): string; 152 | setInfohash(value: string): void; 153 | 154 | getExpire(): number; 155 | setExpire(value: number): void; 156 | 157 | serializeBinary(): Uint8Array; 158 | toObject(includeInstance?: boolean): TouchRequest.AsObject; 159 | static toObject(includeInstance: boolean, msg: TouchRequest): TouchRequest.AsObject; 160 | static extensions: {[key: number]: jspb.ExtensionFieldInfo}; 161 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; 162 | static serializeBinaryToWriter(message: TouchRequest, writer: jspb.BinaryWriter): void; 163 | static deserializeBinary(bytes: Uint8Array): TouchRequest; 164 | static deserializeBinaryFromReader(message: TouchRequest, reader: jspb.BinaryReader): TouchRequest; 165 | } 166 | 167 | export namespace TouchRequest { 168 | export type AsObject = { 169 | infohash: string, 170 | expire: number, 171 | } 172 | } 173 | 174 | -------------------------------------------------------------------------------- /src/sdk/seeder.js: -------------------------------------------------------------------------------- 1 | import stats from './seeder/stats'; 2 | import downloadProgress from './seeder/downloadProgress'; 3 | const debug = require('debug')('webtor:sdk:seeder'); 4 | const Url = require('url-parse'); 5 | var md5 = require('md5'); 6 | 7 | class WebSeeder { 8 | constructor(infoHash, params, sdk) { 9 | this.infoHash = infoHash; 10 | this.params = params; 11 | this.sdk = sdk; 12 | } 13 | 14 | addDownloadId(metadata = {}, path) { 15 | if (!metadata['download-id']) { 16 | metadata = Object.assign({}, metadata, { 17 | 'download-id': md5(metadata['user-id'] + this.infoHash + path + Date.now().toString()), 18 | }); 19 | } 20 | return metadata; 21 | } 22 | 23 | async url(path, metadata = {}, params = {}, context = {}) { 24 | params = Object.assign({}, this.params, params); 25 | path = path.replace(/^\//, ''); 26 | let url = new Url(params.apiUrl); 27 | metadata = this.addDownloadId(metadata, path); 28 | url.infoHash = this.infoHash; 29 | url.path = path; 30 | const pathname = '/' + this.infoHash + '/' + encodeURIComponent(path); 31 | url.infoHash = this.infoHash; 32 | url.set('pathname', pathname); 33 | const query = await this.sdk.util.makeQuery(metadata, params); 34 | url.set('query', query); 35 | 36 | if (params.subdomains) { 37 | url = await this.sdk.util.cacheUrl(url, metadata, params); 38 | const cached = await this.sdk.util.isCached(url, metadata, params); 39 | // const completedPieces = await this.sdk.util.throttledCompletedPieces(url, metadata, params); 40 | // const pieceCache = completedPieces.length > 0; 41 | const deliveryType = this.sdk.util.getDeliveryType(url.pathname); 42 | if (deliveryType === undefined) return url; 43 | let pool = deliveryType == 'transcode' ? params.pools.transcoder : params.pools.seeder; 44 | pool = cached ? params.pools.cache : pool; 45 | const m = { 46 | infohash: this.infoHash, 47 | "use-bandwidth": cached, 48 | "use-cpu": !cached, 49 | "skip-active-job-search": cached, 50 | pool: pool.join(','), 51 | } 52 | const subdomainUrl = await this.sdk.util.subdomainUrl(url, context, m, params); 53 | if (subdomainUrl === false) return false; 54 | subdomainUrl.primaryHost = url.host; 55 | if (subdomainUrl) { 56 | return subdomainUrl; 57 | } 58 | } 59 | return url; 60 | } 61 | 62 | async urlPostProcess(url, metadata, params) { 63 | const cp = await this.completedPieces(metadata, params); 64 | if (cp.length == 0) { 65 | return url; 66 | } 67 | const cdnUrl = this.sdk.util.cdnUrl(url, metadata, params); 68 | if (cdnUrl) { 69 | return cdnUrl; 70 | } 71 | return url; 72 | } 73 | 74 | async streamUrl(path, metadata = {}, params = {}, context = {}) { 75 | params = Object.assign({}, this.params, params); 76 | let url = await this.url(path, metadata, params, context); 77 | url = await this.sdk.util.streamUrl(url, metadata, params, context); 78 | url = await this.urlPostProcess(url, metadata, params); 79 | return url; 80 | } 81 | 82 | async segmentUrl(path, segment, context = {}, metadata = {}, params = {}) { 83 | params = Object.assign({}, this.params, params); 84 | let url = await this.url(path, metadata, params, context); 85 | if (url === false) return false; 86 | url = await this.sdk.util.segmentUrl(url, segment, metadata, params, context); 87 | url = await this.urlPostProcess(url, metadata, params); 88 | return url; 89 | } 90 | 91 | async error(path, metadata = {}, params = {}, context = {}) { 92 | params = Object.assign({}, this.params, params); 93 | let url = await this.url(path, metadata, params, context); 94 | return await this.sdk.util.error(url, metadata, params); 95 | } 96 | 97 | async pieceUrl(id, metadata = {}, params = {}) { 98 | let url = await this.url('', metadata, params); 99 | return this.sdk.util.pieceUrl(url, id); 100 | } 101 | 102 | async mediaInfo(path, metadata = {}, params = {}) { 103 | params = Object.assign({}, this.params, params); 104 | const url = await this.url(path, metadata, params); 105 | return await this.sdk.util.mediaInfo(url, metadata, params); 106 | } 107 | 108 | async completedPieces(metadata = {}, params = {}) { 109 | params = Object.assign({}, this.params, params); 110 | const url = await this.url('', metadata, params); 111 | return await this.sdk.util.throttledCompletedPieces(url, metadata, params); 112 | } 113 | 114 | async isCached(path, metadata = {}, params = {}) { 115 | params = Object.assign({}, this.params, params); 116 | const url = await this.url(path, metadata, params); 117 | const cached = await this.sdk.util.isCached(url, metadata, params); 118 | return cached; 119 | } 120 | 121 | async openSubtitles(path, metadata = {}, params = {}) { 122 | const url = await this.url(path, metadata, params); 123 | return await this.sdk.util.openSubtitles(url); 124 | } 125 | 126 | async downloadUrl(path, metadata = {}, params = {}, context = {}) { 127 | params = Object.assign({}, this.params, params); 128 | if (params.downloadUrl) { 129 | params.apiUrl = params.downloadUrl; 130 | } 131 | metadata.download = true; 132 | let url = await this.url(path, metadata, params, context); 133 | url = await this.urlPostProcess(url, metadata, params); 134 | return url; 135 | } 136 | 137 | async downloadUrlWithProgress(path, onMessage, onEnd, metadata = {}, params = {}, context = {}) { 138 | params = Object.assign({}, this.params, params, {cdn: false}); 139 | metadata = this.addDownloadId(metadata, path); 140 | const downloadUrl = await this.downloadUrl(path, metadata, params, context); 141 | const fileName = path.split('/').pop(); 142 | const url = this.sdk.util.dpUrl(downloadUrl, fileName); 143 | const statUrl = this.sdk.util.dpStatUrl(downloadUrl); 144 | downloadProgress(statUrl, path, onMessage, onEnd, metadata, params); 145 | return url; 146 | } 147 | 148 | async zipUrl(path, metadata = {}, params = {}, context = {}) { 149 | params = Object.assign({}, this.params, params); 150 | if (params.downloadUrl) { 151 | params.apiUrl = params.downloadUrl; 152 | } 153 | const fileName = path.split('/').pop(); 154 | let url = await this.url(path, metadata, params, context); 155 | url.set('pathname', url.pathname + '~arch/' + fileName + '.zip'); 156 | return url; 157 | } 158 | async zipUrlWithProgress(path, onMessage, onEnd, metadata = {}, params = {}, context = {}) { 159 | params = Object.assign({}, this.params, params, {cdn: false}); 160 | metadata = this.addDownloadId(metadata, path); 161 | const zipUrl = await this.zipUrl(path, metadata, params, context); 162 | const fileName = path.split('/').pop() + '.zip'; 163 | const url = this.sdk.util.dpUrl(zipUrl, fileName); 164 | const statUrl = this.sdk.util.dpStatUrl(zipUrl); 165 | downloadProgress(statUrl, path, onMessage, onEnd, metadata, params); 166 | return url; 167 | } 168 | 169 | stats(path, onMessage, metadata = {}, params = {}) { 170 | params = Object.assign({}, this.params, params); 171 | const url = `${params.apiUrl}/${this.infoHash}`; 172 | debug('get file stats infoHash=%s url=%s path=%s metadata=%o', this.infoHash, url, path, metadata); 173 | return stats(url, path, onMessage, metadata, params); 174 | } 175 | } 176 | 177 | export default function(params, sdk) { 178 | const self = {params, sdk}; 179 | return { 180 | get(infoHash, metadata = {}, params = {}) { 181 | params = Object.assign({}, self.params, params); 182 | return new WebSeeder(infoHash, params, self.sdk); 183 | }, 184 | }; 185 | }; -------------------------------------------------------------------------------- /proto/magnet2torrent/magnet2torrent_pb.js: -------------------------------------------------------------------------------- 1 | // source: proto/magnet2torrent/magnet2torrent.proto 2 | /** 3 | * @fileoverview 4 | * @enhanceable 5 | * @suppress {messageConventions} JS Compiler reports an error if a variable or 6 | * field starts with 'MSG_' and isn't a translatable message. 7 | * @public 8 | */ 9 | // GENERATED CODE -- DO NOT EDIT! 10 | /* eslint-disable */ 11 | // @ts-nocheck 12 | 13 | var jspb = require('google-protobuf'); 14 | var goog = jspb; 15 | var proto = {}; 16 | 17 | goog.exportSymbol('Magnet2TorrentReply', null, proto); 18 | goog.exportSymbol('Magnet2TorrentRequest', null, proto); 19 | /** 20 | * Generated by JsPbCodeGenerator. 21 | * @param {Array=} opt_data Optional initial data array, typically from a 22 | * server response, or constructed directly in Javascript. The array is used 23 | * in place and becomes part of the constructed object. It is not cloned. 24 | * If no data is provided, the constructed object will be empty, but still 25 | * valid. 26 | * @extends {jspb.Message} 27 | * @constructor 28 | */ 29 | proto.Magnet2TorrentRequest = function(opt_data) { 30 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 31 | }; 32 | goog.inherits(proto.Magnet2TorrentRequest, jspb.Message); 33 | if (goog.DEBUG && !COMPILED) { 34 | /** 35 | * @public 36 | * @override 37 | */ 38 | proto.Magnet2TorrentRequest.displayName = 'proto.Magnet2TorrentRequest'; 39 | } 40 | /** 41 | * Generated by JsPbCodeGenerator. 42 | * @param {Array=} opt_data Optional initial data array, typically from a 43 | * server response, or constructed directly in Javascript. The array is used 44 | * in place and becomes part of the constructed object. It is not cloned. 45 | * If no data is provided, the constructed object will be empty, but still 46 | * valid. 47 | * @extends {jspb.Message} 48 | * @constructor 49 | */ 50 | proto.Magnet2TorrentReply = function(opt_data) { 51 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 52 | }; 53 | goog.inherits(proto.Magnet2TorrentReply, jspb.Message); 54 | if (goog.DEBUG && !COMPILED) { 55 | /** 56 | * @public 57 | * @override 58 | */ 59 | proto.Magnet2TorrentReply.displayName = 'proto.Magnet2TorrentReply'; 60 | } 61 | 62 | 63 | 64 | if (jspb.Message.GENERATE_TO_OBJECT) { 65 | /** 66 | * Creates an object representation of this proto. 67 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 68 | * Optional fields that are not set will be set to undefined. 69 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 70 | * For the list of reserved names please see: 71 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 72 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 73 | * JSPB instance for transitional soy proto support: 74 | * http://goto/soy-param-migration 75 | * @return {!Object} 76 | */ 77 | proto.Magnet2TorrentRequest.prototype.toObject = function(opt_includeInstance) { 78 | return proto.Magnet2TorrentRequest.toObject(opt_includeInstance, this); 79 | }; 80 | 81 | 82 | /** 83 | * Static version of the {@see toObject} method. 84 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 85 | * the JSPB instance for transitional soy proto support: 86 | * http://goto/soy-param-migration 87 | * @param {!proto.Magnet2TorrentRequest} msg The msg instance to transform. 88 | * @return {!Object} 89 | * @suppress {unusedLocalVariables} f is only used for nested messages 90 | */ 91 | proto.Magnet2TorrentRequest.toObject = function(includeInstance, msg) { 92 | var f, obj = { 93 | magnet: jspb.Message.getFieldWithDefault(msg, 1, "") 94 | }; 95 | 96 | if (includeInstance) { 97 | obj.$jspbMessageInstance = msg; 98 | } 99 | return obj; 100 | }; 101 | } 102 | 103 | 104 | /** 105 | * Deserializes binary data (in protobuf wire format). 106 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 107 | * @return {!proto.Magnet2TorrentRequest} 108 | */ 109 | proto.Magnet2TorrentRequest.deserializeBinary = function(bytes) { 110 | var reader = new jspb.BinaryReader(bytes); 111 | var msg = new proto.Magnet2TorrentRequest; 112 | return proto.Magnet2TorrentRequest.deserializeBinaryFromReader(msg, reader); 113 | }; 114 | 115 | 116 | /** 117 | * Deserializes binary data (in protobuf wire format) from the 118 | * given reader into the given message object. 119 | * @param {!proto.Magnet2TorrentRequest} msg The message object to deserialize into. 120 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 121 | * @return {!proto.Magnet2TorrentRequest} 122 | */ 123 | proto.Magnet2TorrentRequest.deserializeBinaryFromReader = function(msg, reader) { 124 | while (reader.nextField()) { 125 | if (reader.isEndGroup()) { 126 | break; 127 | } 128 | var field = reader.getFieldNumber(); 129 | switch (field) { 130 | case 1: 131 | var value = /** @type {string} */ (reader.readString()); 132 | msg.setMagnet(value); 133 | break; 134 | default: 135 | reader.skipField(); 136 | break; 137 | } 138 | } 139 | return msg; 140 | }; 141 | 142 | 143 | /** 144 | * Serializes the message to binary data (in protobuf wire format). 145 | * @return {!Uint8Array} 146 | */ 147 | proto.Magnet2TorrentRequest.prototype.serializeBinary = function() { 148 | var writer = new jspb.BinaryWriter(); 149 | proto.Magnet2TorrentRequest.serializeBinaryToWriter(this, writer); 150 | return writer.getResultBuffer(); 151 | }; 152 | 153 | 154 | /** 155 | * Serializes the given message to binary data (in protobuf wire 156 | * format), writing to the given BinaryWriter. 157 | * @param {!proto.Magnet2TorrentRequest} message 158 | * @param {!jspb.BinaryWriter} writer 159 | * @suppress {unusedLocalVariables} f is only used for nested messages 160 | */ 161 | proto.Magnet2TorrentRequest.serializeBinaryToWriter = function(message, writer) { 162 | var f = undefined; 163 | f = message.getMagnet(); 164 | if (f.length > 0) { 165 | writer.writeString( 166 | 1, 167 | f 168 | ); 169 | } 170 | }; 171 | 172 | 173 | /** 174 | * optional string magnet = 1; 175 | * @return {string} 176 | */ 177 | proto.Magnet2TorrentRequest.prototype.getMagnet = function() { 178 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 179 | }; 180 | 181 | 182 | /** 183 | * @param {string} value 184 | * @return {!proto.Magnet2TorrentRequest} returns this 185 | */ 186 | proto.Magnet2TorrentRequest.prototype.setMagnet = function(value) { 187 | return jspb.Message.setProto3StringField(this, 1, value); 188 | }; 189 | 190 | 191 | 192 | 193 | 194 | if (jspb.Message.GENERATE_TO_OBJECT) { 195 | /** 196 | * Creates an object representation of this proto. 197 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 198 | * Optional fields that are not set will be set to undefined. 199 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 200 | * For the list of reserved names please see: 201 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 202 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 203 | * JSPB instance for transitional soy proto support: 204 | * http://goto/soy-param-migration 205 | * @return {!Object} 206 | */ 207 | proto.Magnet2TorrentReply.prototype.toObject = function(opt_includeInstance) { 208 | return proto.Magnet2TorrentReply.toObject(opt_includeInstance, this); 209 | }; 210 | 211 | 212 | /** 213 | * Static version of the {@see toObject} method. 214 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 215 | * the JSPB instance for transitional soy proto support: 216 | * http://goto/soy-param-migration 217 | * @param {!proto.Magnet2TorrentReply} msg The msg instance to transform. 218 | * @return {!Object} 219 | * @suppress {unusedLocalVariables} f is only used for nested messages 220 | */ 221 | proto.Magnet2TorrentReply.toObject = function(includeInstance, msg) { 222 | var f, obj = { 223 | torrent: msg.getTorrent_asB64() 224 | }; 225 | 226 | if (includeInstance) { 227 | obj.$jspbMessageInstance = msg; 228 | } 229 | return obj; 230 | }; 231 | } 232 | 233 | 234 | /** 235 | * Deserializes binary data (in protobuf wire format). 236 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 237 | * @return {!proto.Magnet2TorrentReply} 238 | */ 239 | proto.Magnet2TorrentReply.deserializeBinary = function(bytes) { 240 | var reader = new jspb.BinaryReader(bytes); 241 | var msg = new proto.Magnet2TorrentReply; 242 | return proto.Magnet2TorrentReply.deserializeBinaryFromReader(msg, reader); 243 | }; 244 | 245 | 246 | /** 247 | * Deserializes binary data (in protobuf wire format) from the 248 | * given reader into the given message object. 249 | * @param {!proto.Magnet2TorrentReply} msg The message object to deserialize into. 250 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 251 | * @return {!proto.Magnet2TorrentReply} 252 | */ 253 | proto.Magnet2TorrentReply.deserializeBinaryFromReader = function(msg, reader) { 254 | while (reader.nextField()) { 255 | if (reader.isEndGroup()) { 256 | break; 257 | } 258 | var field = reader.getFieldNumber(); 259 | switch (field) { 260 | case 1: 261 | var value = /** @type {!Uint8Array} */ (reader.readBytes()); 262 | msg.setTorrent(value); 263 | break; 264 | default: 265 | reader.skipField(); 266 | break; 267 | } 268 | } 269 | return msg; 270 | }; 271 | 272 | 273 | /** 274 | * Serializes the message to binary data (in protobuf wire format). 275 | * @return {!Uint8Array} 276 | */ 277 | proto.Magnet2TorrentReply.prototype.serializeBinary = function() { 278 | var writer = new jspb.BinaryWriter(); 279 | proto.Magnet2TorrentReply.serializeBinaryToWriter(this, writer); 280 | return writer.getResultBuffer(); 281 | }; 282 | 283 | 284 | /** 285 | * Serializes the given message to binary data (in protobuf wire 286 | * format), writing to the given BinaryWriter. 287 | * @param {!proto.Magnet2TorrentReply} message 288 | * @param {!jspb.BinaryWriter} writer 289 | * @suppress {unusedLocalVariables} f is only used for nested messages 290 | */ 291 | proto.Magnet2TorrentReply.serializeBinaryToWriter = function(message, writer) { 292 | var f = undefined; 293 | f = message.getTorrent_asU8(); 294 | if (f.length > 0) { 295 | writer.writeBytes( 296 | 1, 297 | f 298 | ); 299 | } 300 | }; 301 | 302 | 303 | /** 304 | * optional bytes torrent = 1; 305 | * @return {!(string|Uint8Array)} 306 | */ 307 | proto.Magnet2TorrentReply.prototype.getTorrent = function() { 308 | return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 309 | }; 310 | 311 | 312 | /** 313 | * optional bytes torrent = 1; 314 | * This is a type-conversion wrapper around `getTorrent()` 315 | * @return {string} 316 | */ 317 | proto.Magnet2TorrentReply.prototype.getTorrent_asB64 = function() { 318 | return /** @type {string} */ (jspb.Message.bytesAsB64( 319 | this.getTorrent())); 320 | }; 321 | 322 | 323 | /** 324 | * optional bytes torrent = 1; 325 | * Note that Uint8Array is not supported on all browsers. 326 | * @see http://caniuse.com/Uint8Array 327 | * This is a type-conversion wrapper around `getTorrent()` 328 | * @return {!Uint8Array} 329 | */ 330 | proto.Magnet2TorrentReply.prototype.getTorrent_asU8 = function() { 331 | return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( 332 | this.getTorrent())); 333 | }; 334 | 335 | 336 | /** 337 | * @param {!(string|Uint8Array)} value 338 | * @return {!proto.Magnet2TorrentReply} returns this 339 | */ 340 | proto.Magnet2TorrentReply.prototype.setTorrent = function(value) { 341 | return jspb.Message.setProto3BytesField(this, 1, value); 342 | }; 343 | 344 | 345 | goog.object.extend(exports, proto); 346 | -------------------------------------------------------------------------------- /proto/download-progress/download-progress_pb.js: -------------------------------------------------------------------------------- 1 | // source: proto/download-progress/download-progress.proto 2 | /** 3 | * @fileoverview 4 | * @enhanceable 5 | * @suppress {messageConventions} JS Compiler reports an error if a variable or 6 | * field starts with 'MSG_' and isn't a translatable message. 7 | * @public 8 | */ 9 | // GENERATED CODE -- DO NOT EDIT! 10 | /* eslint-disable */ 11 | // @ts-nocheck 12 | 13 | var jspb = require('google-protobuf'); 14 | var goog = jspb; 15 | var proto = {}; 16 | 17 | goog.exportSymbol('StatReply', null, proto); 18 | goog.exportSymbol('StatReply.Status', null, proto); 19 | goog.exportSymbol('StatRequest', null, proto); 20 | /** 21 | * Generated by JsPbCodeGenerator. 22 | * @param {Array=} opt_data Optional initial data array, typically from a 23 | * server response, or constructed directly in Javascript. The array is used 24 | * in place and becomes part of the constructed object. It is not cloned. 25 | * If no data is provided, the constructed object will be empty, but still 26 | * valid. 27 | * @extends {jspb.Message} 28 | * @constructor 29 | */ 30 | proto.StatRequest = function(opt_data) { 31 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 32 | }; 33 | goog.inherits(proto.StatRequest, jspb.Message); 34 | if (goog.DEBUG && !COMPILED) { 35 | /** 36 | * @public 37 | * @override 38 | */ 39 | proto.StatRequest.displayName = 'proto.StatRequest'; 40 | } 41 | /** 42 | * Generated by JsPbCodeGenerator. 43 | * @param {Array=} opt_data Optional initial data array, typically from a 44 | * server response, or constructed directly in Javascript. The array is used 45 | * in place and becomes part of the constructed object. It is not cloned. 46 | * If no data is provided, the constructed object will be empty, but still 47 | * valid. 48 | * @extends {jspb.Message} 49 | * @constructor 50 | */ 51 | proto.StatReply = function(opt_data) { 52 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 53 | }; 54 | goog.inherits(proto.StatReply, jspb.Message); 55 | if (goog.DEBUG && !COMPILED) { 56 | /** 57 | * @public 58 | * @override 59 | */ 60 | proto.StatReply.displayName = 'proto.StatReply'; 61 | } 62 | 63 | 64 | 65 | if (jspb.Message.GENERATE_TO_OBJECT) { 66 | /** 67 | * Creates an object representation of this proto. 68 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 69 | * Optional fields that are not set will be set to undefined. 70 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 71 | * For the list of reserved names please see: 72 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 73 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 74 | * JSPB instance for transitional soy proto support: 75 | * http://goto/soy-param-migration 76 | * @return {!Object} 77 | */ 78 | proto.StatRequest.prototype.toObject = function(opt_includeInstance) { 79 | return proto.StatRequest.toObject(opt_includeInstance, this); 80 | }; 81 | 82 | 83 | /** 84 | * Static version of the {@see toObject} method. 85 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 86 | * the JSPB instance for transitional soy proto support: 87 | * http://goto/soy-param-migration 88 | * @param {!proto.StatRequest} msg The msg instance to transform. 89 | * @return {!Object} 90 | * @suppress {unusedLocalVariables} f is only used for nested messages 91 | */ 92 | proto.StatRequest.toObject = function(includeInstance, msg) { 93 | var f, obj = { 94 | 95 | }; 96 | 97 | if (includeInstance) { 98 | obj.$jspbMessageInstance = msg; 99 | } 100 | return obj; 101 | }; 102 | } 103 | 104 | 105 | /** 106 | * Deserializes binary data (in protobuf wire format). 107 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 108 | * @return {!proto.StatRequest} 109 | */ 110 | proto.StatRequest.deserializeBinary = function(bytes) { 111 | var reader = new jspb.BinaryReader(bytes); 112 | var msg = new proto.StatRequest; 113 | return proto.StatRequest.deserializeBinaryFromReader(msg, reader); 114 | }; 115 | 116 | 117 | /** 118 | * Deserializes binary data (in protobuf wire format) from the 119 | * given reader into the given message object. 120 | * @param {!proto.StatRequest} msg The message object to deserialize into. 121 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 122 | * @return {!proto.StatRequest} 123 | */ 124 | proto.StatRequest.deserializeBinaryFromReader = function(msg, reader) { 125 | while (reader.nextField()) { 126 | if (reader.isEndGroup()) { 127 | break; 128 | } 129 | var field = reader.getFieldNumber(); 130 | switch (field) { 131 | default: 132 | reader.skipField(); 133 | break; 134 | } 135 | } 136 | return msg; 137 | }; 138 | 139 | 140 | /** 141 | * Serializes the message to binary data (in protobuf wire format). 142 | * @return {!Uint8Array} 143 | */ 144 | proto.StatRequest.prototype.serializeBinary = function() { 145 | var writer = new jspb.BinaryWriter(); 146 | proto.StatRequest.serializeBinaryToWriter(this, writer); 147 | return writer.getResultBuffer(); 148 | }; 149 | 150 | 151 | /** 152 | * Serializes the given message to binary data (in protobuf wire 153 | * format), writing to the given BinaryWriter. 154 | * @param {!proto.StatRequest} message 155 | * @param {!jspb.BinaryWriter} writer 156 | * @suppress {unusedLocalVariables} f is only used for nested messages 157 | */ 158 | proto.StatRequest.serializeBinaryToWriter = function(message, writer) { 159 | var f = undefined; 160 | }; 161 | 162 | 163 | 164 | 165 | 166 | if (jspb.Message.GENERATE_TO_OBJECT) { 167 | /** 168 | * Creates an object representation of this proto. 169 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 170 | * Optional fields that are not set will be set to undefined. 171 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 172 | * For the list of reserved names please see: 173 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 174 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 175 | * JSPB instance for transitional soy proto support: 176 | * http://goto/soy-param-migration 177 | * @return {!Object} 178 | */ 179 | proto.StatReply.prototype.toObject = function(opt_includeInstance) { 180 | return proto.StatReply.toObject(opt_includeInstance, this); 181 | }; 182 | 183 | 184 | /** 185 | * Static version of the {@see toObject} method. 186 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 187 | * the JSPB instance for transitional soy proto support: 188 | * http://goto/soy-param-migration 189 | * @param {!proto.StatReply} msg The msg instance to transform. 190 | * @return {!Object} 191 | * @suppress {unusedLocalVariables} f is only used for nested messages 192 | */ 193 | proto.StatReply.toObject = function(includeInstance, msg) { 194 | var f, obj = { 195 | status: jspb.Message.getFieldWithDefault(msg, 1, 0), 196 | downloaded: jspb.Message.getFieldWithDefault(msg, 2, 0), 197 | rate: jspb.Message.getFieldWithDefault(msg, 3, 0), 198 | length: jspb.Message.getFieldWithDefault(msg, 4, 0) 199 | }; 200 | 201 | if (includeInstance) { 202 | obj.$jspbMessageInstance = msg; 203 | } 204 | return obj; 205 | }; 206 | } 207 | 208 | 209 | /** 210 | * Deserializes binary data (in protobuf wire format). 211 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 212 | * @return {!proto.StatReply} 213 | */ 214 | proto.StatReply.deserializeBinary = function(bytes) { 215 | var reader = new jspb.BinaryReader(bytes); 216 | var msg = new proto.StatReply; 217 | return proto.StatReply.deserializeBinaryFromReader(msg, reader); 218 | }; 219 | 220 | 221 | /** 222 | * Deserializes binary data (in protobuf wire format) from the 223 | * given reader into the given message object. 224 | * @param {!proto.StatReply} msg The message object to deserialize into. 225 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 226 | * @return {!proto.StatReply} 227 | */ 228 | proto.StatReply.deserializeBinaryFromReader = function(msg, reader) { 229 | while (reader.nextField()) { 230 | if (reader.isEndGroup()) { 231 | break; 232 | } 233 | var field = reader.getFieldNumber(); 234 | switch (field) { 235 | case 1: 236 | var value = /** @type {!proto.StatReply.Status} */ (reader.readEnum()); 237 | msg.setStatus(value); 238 | break; 239 | case 2: 240 | var value = /** @type {number} */ (reader.readInt64()); 241 | msg.setDownloaded(value); 242 | break; 243 | case 3: 244 | var value = /** @type {number} */ (reader.readInt64()); 245 | msg.setRate(value); 246 | break; 247 | case 4: 248 | var value = /** @type {number} */ (reader.readInt64()); 249 | msg.setLength(value); 250 | break; 251 | default: 252 | reader.skipField(); 253 | break; 254 | } 255 | } 256 | return msg; 257 | }; 258 | 259 | 260 | /** 261 | * Serializes the message to binary data (in protobuf wire format). 262 | * @return {!Uint8Array} 263 | */ 264 | proto.StatReply.prototype.serializeBinary = function() { 265 | var writer = new jspb.BinaryWriter(); 266 | proto.StatReply.serializeBinaryToWriter(this, writer); 267 | return writer.getResultBuffer(); 268 | }; 269 | 270 | 271 | /** 272 | * Serializes the given message to binary data (in protobuf wire 273 | * format), writing to the given BinaryWriter. 274 | * @param {!proto.StatReply} message 275 | * @param {!jspb.BinaryWriter} writer 276 | * @suppress {unusedLocalVariables} f is only used for nested messages 277 | */ 278 | proto.StatReply.serializeBinaryToWriter = function(message, writer) { 279 | var f = undefined; 280 | f = message.getStatus(); 281 | if (f !== 0.0) { 282 | writer.writeEnum( 283 | 1, 284 | f 285 | ); 286 | } 287 | f = message.getDownloaded(); 288 | if (f !== 0) { 289 | writer.writeInt64( 290 | 2, 291 | f 292 | ); 293 | } 294 | f = message.getRate(); 295 | if (f !== 0) { 296 | writer.writeInt64( 297 | 3, 298 | f 299 | ); 300 | } 301 | f = message.getLength(); 302 | if (f !== 0) { 303 | writer.writeInt64( 304 | 4, 305 | f 306 | ); 307 | } 308 | }; 309 | 310 | 311 | /** 312 | * @enum {number} 313 | */ 314 | proto.StatReply.Status = { 315 | NOT_STARTED: 0, 316 | PENDING: 1, 317 | ACTIVE: 2, 318 | DONE: 3, 319 | FAILED: 4 320 | }; 321 | 322 | /** 323 | * optional Status status = 1; 324 | * @return {!proto.StatReply.Status} 325 | */ 326 | proto.StatReply.prototype.getStatus = function() { 327 | return /** @type {!proto.StatReply.Status} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); 328 | }; 329 | 330 | 331 | /** 332 | * @param {!proto.StatReply.Status} value 333 | * @return {!proto.StatReply} returns this 334 | */ 335 | proto.StatReply.prototype.setStatus = function(value) { 336 | return jspb.Message.setProto3EnumField(this, 1, value); 337 | }; 338 | 339 | 340 | /** 341 | * optional int64 downloaded = 2; 342 | * @return {number} 343 | */ 344 | proto.StatReply.prototype.getDownloaded = function() { 345 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); 346 | }; 347 | 348 | 349 | /** 350 | * @param {number} value 351 | * @return {!proto.StatReply} returns this 352 | */ 353 | proto.StatReply.prototype.setDownloaded = function(value) { 354 | return jspb.Message.setProto3IntField(this, 2, value); 355 | }; 356 | 357 | 358 | /** 359 | * optional int64 rate = 3; 360 | * @return {number} 361 | */ 362 | proto.StatReply.prototype.getRate = function() { 363 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); 364 | }; 365 | 366 | 367 | /** 368 | * @param {number} value 369 | * @return {!proto.StatReply} returns this 370 | */ 371 | proto.StatReply.prototype.setRate = function(value) { 372 | return jspb.Message.setProto3IntField(this, 3, value); 373 | }; 374 | 375 | 376 | /** 377 | * optional int64 length = 4; 378 | * @return {number} 379 | */ 380 | proto.StatReply.prototype.getLength = function() { 381 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); 382 | }; 383 | 384 | 385 | /** 386 | * @param {number} value 387 | * @return {!proto.StatReply} returns this 388 | */ 389 | proto.StatReply.prototype.setLength = function(value) { 390 | return jspb.Message.setProto3IntField(this, 4, value); 391 | }; 392 | 393 | 394 | goog.object.extend(exports, proto); 395 | -------------------------------------------------------------------------------- /src/sdk/util.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Url = require('url-parse'); 3 | import ISO6391 from 'iso-639-1'; 4 | import mime from 'mime'; 5 | var md5 = require('md5'); 6 | const debug = require('debug')('webtor:sdk:util'); 7 | import bind from 'lodash/bind'; 8 | import throttle from 'lodash/throttle'; 9 | const debugFetch = function(url) { 10 | debug('fetch url=%o', url.href); 11 | return fetch(url); 12 | } 13 | const retryFetch = require('fetch-retry')(debugFetch, { 14 | retries: 3, 15 | retryDelay: function(attempt, error, response) { 16 | return Math.pow(2, attempt) * 1000; 17 | }, 18 | retryOn: function(attempt, error, response) { 19 | if (error !== null || response.status >= 500) { 20 | debug('got fetch error retry count=%o', attempt); 21 | return true; 22 | } 23 | }, 24 | }); 25 | 26 | function cleanExt(ext) { 27 | return ext.toLowerCase().replace(/~[a-z0-9]+$/, ''); 28 | } 29 | function cleanPath(p) { 30 | return p.replace(/\/\//, '/'); 31 | } 32 | function buf2hex(buffer) { // buffer is an ArrayBuffer 33 | return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); 34 | } 35 | 36 | export default function(params, sdk) { 37 | const self = {params, sdk}; 38 | const throttledFuncs = {}; 39 | const util = { 40 | async makeQuery(metadata = {}, params = {}) { 41 | params = Object.assign({}, self.params, params); 42 | metadata = Object.assign({}, metadata); 43 | const query = metadata; 44 | const token = await params.getToken(); 45 | if (token) query.token = token; 46 | if (params.apiKey) query["api-key"] = params.apiKey; 47 | return query; 48 | }, 49 | getDeliveryType(file) { 50 | if (!file) return; 51 | let ext = path.extname(file); 52 | ext = cleanExt(ext); 53 | // Browser unsupported streaming formats 54 | if ('.avi .mkv .flac .m4a .m4v .ts .vob'.split(' ').includes(ext)) return 'transcode'; 55 | // Browser supported streaming formats 56 | if ('.mp4 .mp3 .wav .ogg .webm'.split(' ').includes(ext)) return 'webseed'; 57 | // Browser supported image formats 58 | if ('.png .gif .jpg .jpeg'.split(' ').includes(ext)) return 'webseed'; 59 | // Browser unsupported subtitle formats 60 | if ('.vtt .srt'.split(' ').includes(ext)) return 'webseed'; 61 | }, 62 | getMediaType(file) { 63 | if (!file) return; 64 | let ext = path.extname(file); 65 | ext = cleanExt(ext); 66 | // Video 67 | if ('.avi .mkv .mp4 .webm .m4v .ts .vob'.split(' ').includes(ext)) return 'video'; 68 | // Audio 69 | if ('.mp3 .wav .ogg .flac .m4a'.split(' ').includes(ext)) return 'audio'; 70 | // Images 71 | if ('.png .gif .jpg .jpeg'.split(' ').includes(ext)) return 'image'; 72 | // Subtitles 73 | if ('.srt .vtt'.split(' ').includes(ext)) return 'subtitle'; 74 | }, 75 | getMimeType(file) { 76 | if (typeof file == 'object') { 77 | file = file.pathname; 78 | } 79 | const ext = path.extname(file); 80 | return mime.getType(ext); 81 | }, 82 | getSubtitleSrcLang(name) { 83 | const baseName = path.basename(name, path.extname(name)); 84 | for (const code of ISO6391.getAllCodes()) { 85 | if (baseName.endsWith('.' + code)) return code; 86 | } 87 | return false; 88 | }, 89 | getSubtitleLang(name) { 90 | const code = this.getSubtitleSrcLang(name); 91 | if (code == false) return false; 92 | return this.getLang(code); 93 | }, 94 | getLang(code) { 95 | return { 96 | code, 97 | name: ISO6391.getName(code), 98 | nativeName: ISO6391.getNativeName(code), 99 | }; 100 | }, 101 | cloneUrl(url) { 102 | return Object.assign(new Url(), url); 103 | }, 104 | vttUrl(url) { 105 | url = this.cloneUrl(url); 106 | url.set('pathname', cleanPath(url.pathname + '~vtt/' + encodeURIComponent(path.basename(url.pathname).replace(/srt$/, 'vtt')))); 107 | return url; 108 | }, 109 | primaryUrl(url) { 110 | if (!url) return url; 111 | url = this.cloneUrl(url); 112 | if (url.primaryHost) { 113 | url.host = url.primaryHost; 114 | } 115 | return url; 116 | }, 117 | completedPiecesUrl(url) { 118 | url = this.cloneUrl(url); 119 | url = this.tcUrl(url); 120 | url.set('pathname', cleanPath(url.pathname.replace(/~tc.*$/, '~tc/completed_pieces'))); 121 | return url; 122 | }, 123 | transcodeDoneMarkerUrl(url) { 124 | url = this.cloneUrl(url); 125 | url = this.primaryUrl(url); 126 | url.set('pathname', cleanPath(url.pathname + '~trc/done')); 127 | return url; 128 | }, 129 | multibitrateDoneMarkerUrl(url) { 130 | url = this.cloneUrl(url); 131 | url = this.primaryUrl(url); 132 | url.set('pathname', cleanPath(url.pathname + '~mtrc/done')); 133 | return url; 134 | }, 135 | transcodeIndexUrl(url) { 136 | url = this.cloneUrl(url); 137 | url.set('pathname', cleanPath(url.pathname + '~trc/index.m3u8')); 138 | return url; 139 | }, 140 | multibitrateIndexUrl(url) { 141 | url = this.cloneUrl(url); 142 | url.set('pathname', cleanPath(url.pathname + '~mtrc/index.m3u8')); 143 | return url; 144 | }, 145 | pieceUrl(url, id) { 146 | url = this.cloneUrl(url); 147 | url.set('pathname', cleanPath(url.pathname + '/piece/' + id)); 148 | return url; 149 | }, 150 | tcUrl(url) { 151 | url = this.cloneUrl(url); 152 | if (url.pathname.includes('~tc')) return url; 153 | url.set('pathname', cleanPath(url.pathname + '~tc/' + encodeURIComponent(path.basename(url.path)))); 154 | return url; 155 | }, 156 | hlsUrl(url, file) { 157 | url = this.cloneUrl(url); 158 | url.set('pathname', cleanPath(url.pathname + '~hls/' + file)); 159 | return url; 160 | }, 161 | trcUrl(url, file) { 162 | url = this.cloneUrl(url); 163 | url.set('pathname', cleanPath(url.pathname + '~trc/' + file)); 164 | return url; 165 | }, 166 | mtrcUrl(url, file) { 167 | url = this.cloneUrl(url); 168 | url.set('pathname', cleanPath(url.pathname + '~mtrc/' + file)); 169 | return url; 170 | }, 171 | vodUrl(url, file) { 172 | url = this.cloneUrl(url); 173 | url.set('pathname', cleanPath(url.pathname + '~vod/hls/' + md5(cleanPath(url.pathname)) + '/' + file)); 174 | return url; 175 | }, 176 | viUrl(url, path) { 177 | url = this.cloneUrl(url); 178 | url.set('pathname', cleanPath(url.pathname + '~vi' + path)); 179 | return url; 180 | }, 181 | dpUrl(url, file) { 182 | url = this.cloneUrl(url); 183 | url.set('pathname', cleanPath(url.pathname + '~dp/' + file)); 184 | return url; 185 | }, 186 | dpStatUrl(url) { 187 | url = this.cloneUrl(url); 188 | url.set('pathname', '/dp'); 189 | url.set('query', ''); 190 | return url; 191 | }, 192 | async baseStreamUrl(url, file, metadata, params, context) { 193 | url = this.cloneUrl(url); 194 | const deliveryType = this.getDeliveryType(url.pathname); 195 | if (params.vod && cleanExt(path.extname(url.pathname)) == '.mp4') { 196 | if (params.multibitrate) { 197 | const done = await this.throttledMultibitrateDoneMarker(url, metadata, params); 198 | if (done) { 199 | url.multibitrate = true; 200 | url.cached = true; 201 | return this.mtrcUrl(url, file); 202 | } 203 | } 204 | return this.vodUrl(url, file); 205 | } else if (cleanExt(path.extname(url.pathname)) == '.srt') { 206 | return this.vttUrl(url); 207 | } else if (deliveryType == 'transcode') { 208 | if (params.multibitrate) { 209 | const done = await this.throttledMultibitrateDoneMarker(url, metadata, params); 210 | if (done) { 211 | url.multibitrate = true; 212 | url.cached = true; 213 | return this.mtrcUrl(url, file); 214 | } 215 | } 216 | if (params.cache) { 217 | const done = await this.throttledTranscodeDoneMarker(url, metadata, params); 218 | if (done) { 219 | url.cached = true; 220 | return this.trcUrl(url, file); 221 | } 222 | } 223 | return this.hlsUrl(url, file); 224 | } 225 | return url; 226 | }, 227 | async streamUrl(url, metadata, params, context) { 228 | return this.baseStreamUrl(url, 'index.m3u8', metadata, params, context); 229 | }, 230 | async segmentUrl(url, segment, metadata, params, context) { 231 | return this.baseStreamUrl(url, segment, metadata, params, context); 232 | }, 233 | async error(url, metadata, params) { 234 | url = this.cloneUrl(url); 235 | const deliveryType = this.getDeliveryType(url.pathname); 236 | const mediaType = this.getMediaType(url.pathname); 237 | if (deliveryType == 'webseed' || mediaType == 'subtitle') return; 238 | if (params.cache) { 239 | const done = await this.throttledTranscodeDoneMarker(url, metadata, params); 240 | if (done) { 241 | return; 242 | } else { 243 | url = this.hlsUrl(url, 'error.log'); 244 | } 245 | } else { 246 | url = this.hlsUrl(url, 'error.log'); 247 | } 248 | const res = await fetch(url); 249 | const err = await res.text(); 250 | return err; 251 | }, 252 | async transcodeDoneMarker(url) { 253 | url = this.cloneUrl(url); 254 | url = this.transcodeDoneMarkerUrl(url); 255 | const res = await(retryFetch(url)); 256 | return res.status == 200; 257 | }, 258 | async multibitrateDoneMarker(url) { 259 | url = this.cloneUrl(url); 260 | url = this.multibitrateDoneMarkerUrl(url); 261 | const res = await(retryFetch(url)); 262 | return res.status == 200; 263 | }, 264 | 265 | async transcodeIndexExists(url) { 266 | url = this.cloneUrl(url); 267 | url = this.transcodeIndexUrl(url); 268 | const res = await(retryFetch(url)); 269 | return res.status == 200; 270 | }, 271 | 272 | async multibitrateIndexExists(url) { 273 | url = this.cloneUrl(url); 274 | url = this.multibitrateIndexUrl(url); 275 | const res = await(retryFetch(url)); 276 | return res.status == 200; 277 | }, 278 | 279 | async completedPieces(url) { 280 | url = this.cloneUrl(url); 281 | url = this.completedPiecesUrl(url); 282 | const res = await(retryFetch(url)); 283 | const buf = await res.arrayBuffer(); 284 | const byteArr = new Uint8Array(buf); 285 | const hex = buf2hex(byteArr); 286 | const pieces = []; 287 | let p = ''; 288 | for (const c of hex) { 289 | p += c; 290 | if (p.length == 40) { 291 | pieces.push(p); 292 | p = ''; 293 | } 294 | } 295 | return pieces; 296 | }, 297 | 298 | async mediaInfo(url, metadata = {}, params = {}) { 299 | url = this.cloneUrl(url); 300 | const deliveryType = this.getDeliveryType(url.pathname); 301 | const mediaType = this.getMediaType(url.pathname); 302 | if (deliveryType == 'webseed' || mediaType == 'subtitle') return {}; 303 | if (params.cache) { 304 | const done = await this.throttledTranscodeDoneMarker(url, metadata, params); 305 | if (done) { 306 | url = this.trcUrl(url, 'index.json'); 307 | } else { 308 | url = this.hlsUrl(url, 'index.json'); 309 | } 310 | } else { 311 | url = this.hlsUrl(url, 'index.json'); 312 | } 313 | const res = await(retryFetch(url)); 314 | const mediaInfo = await res.json(); 315 | return mediaInfo; 316 | }, 317 | async openSubtitles(url) { 318 | url = this.cloneUrl(url); 319 | const mediaType = this.getMediaType(url.pathname); 320 | if (mediaType != 'video') return {}; 321 | const subtitlesUrl = this.viUrl(url, '/subtitles.json'); 322 | const res = await(retryFetch(subtitlesUrl)); 323 | const data = await res.json(); 324 | 325 | for (const k in data) { 326 | const format = data[k].format; 327 | if (format != 'srt' && format != 'vtt') continue; 328 | let src = data[k].src; 329 | let sUrl = this.viUrl(url, src); 330 | if (format != 'vtt') { 331 | sUrl = this.vttUrl(sUrl); 332 | } 333 | data[k].src = sUrl 334 | } 335 | return data; 336 | }, 337 | async subdomainsUrl(metadata = {}, params = {}) { 338 | params = Object.assign({}, self.params, params); 339 | const url = new Url(params.apiUrl); 340 | const pathname = '/subdomains.json'; 341 | url.set('pathname', pathname); 342 | const query = await self.sdk.util.makeQuery(metadata, params); 343 | url.set('query', query); 344 | return url; 345 | }, 346 | async subdomains(u, path, metadata = {}, params = {}) { 347 | params = Object.assign({}, self.params, params); 348 | const url = await this.subdomainsUrl(metadata, params); 349 | const res = await(retryFetch(url)); 350 | const s = await res.json(); 351 | const rr = []; 352 | for (const e of s) { 353 | rr.push(e); 354 | } 355 | return rr; 356 | }, 357 | isCDNAllowed(path, params = {}) { 358 | params = Object.assign({}, self.params, params); 359 | for (const a of params.cdnPathSuffixes) { 360 | if (cleanExt(path).endsWith(a)) return true; 361 | } 362 | return false; 363 | }, 364 | cdnUrl(url, metadata = {}, params = {}) { 365 | url = this.cloneUrl(url); 366 | params = Object.assign({}, self.params, params); 367 | if (params.cdn && params.cdnUrl && this.isCDNAllowed(url.pathname, params)) { 368 | let cdnUrl = new Url(params.cdnUrl); 369 | url.set('hostname', cdnUrl.hostname); 370 | url.set('protocol', cdnUrl.protocol); 371 | url.set('query', '?api-key=' + params.apiKey); 372 | return url; 373 | } 374 | return false; 375 | }, 376 | async throttled(func, interval, url, file, metadata, params, k) { 377 | let key = url.infoHash + file + func.name; 378 | if (k) key += k; 379 | if (!throttledFuncs[key]) { 380 | throttledFuncs[key] = throttle(bind(func, this, url, file, metadata, params), interval, { 381 | trailing: false, 382 | }); 383 | } 384 | const tf = throttledFuncs[key]; 385 | return await tf(); 386 | }, 387 | async cacheUrl(url, metadata, params) { 388 | const completedPieces = await this.throttledCompletedPieces(url, metadata, params); 389 | if (completedPieces.length > 0) { 390 | return this.tcUrl(url); 391 | } 392 | return url; 393 | 394 | }, 395 | async throttledCompletedPieces(url, metadata = {}, params = {}) { 396 | let completedPieces = []; 397 | if (params.cache) { 398 | completedPieces = await this.throttled(this.completedPieces, 10*60*1000, url, null, metadata, params); 399 | } 400 | return completedPieces; 401 | }, 402 | async throttledTranscodeIndexExists(url, metadata = {}, params = {}) { 403 | let done = false; 404 | if (params.cache) { 405 | done = await this.throttled(this.transcodeIndexExists, 10*60*1000, url, url.path, metadata, params); 406 | } 407 | return done; 408 | }, 409 | async throttledTranscodeDoneMarker(url, metadata = {}, params = {}) { 410 | let done = false; 411 | if (params.cache) { 412 | done = await this.throttled(this.transcodeDoneMarker, 10*60*1000, url, url.path, metadata, params); 413 | } 414 | return done; 415 | }, 416 | async throttledMultibitrateDoneMarker(url, metadata = {}, params = {}) { 417 | let done = false; 418 | if (params.cache) { 419 | done = await this.throttled(this.multibitrateDoneMarker, 10*60*1000, url, url.path, metadata, params); 420 | } 421 | return done; 422 | }, 423 | async throttledMultibitrateIndexExists(url, metadata = {}, params = {}) { 424 | let done = false; 425 | if (params.cache) { 426 | done = await this.throttled(this.multibitrateIndexExists, 10*60*1000, url, url.path, metadata, params); 427 | } 428 | return done; 429 | }, 430 | async isCached(url, metadata = {}, params = {}) { 431 | const deliveryType = this.getDeliveryType(url.pathname); 432 | const mediaType = this.getMediaType(url.pathname); 433 | if (mediaType == 'video') { 434 | if (await this.throttledMultibitrateDoneMarker(url, metadata, params)) return true; 435 | } 436 | if (deliveryType == 'transcode') { 437 | if (await this.throttledTranscodeDoneMarker(url, metadata, params)) return true; 438 | } 439 | if (deliveryType == 'webseed') { 440 | const completedPieces = await this.throttledCompletedPieces(url, metadata, params); 441 | return completedPieces.length > 0; 442 | } 443 | return false; 444 | }, 445 | async subdomainUrl(url, context = {}, metadata = {}, params = {}) { 446 | url = this.cloneUrl(url); 447 | params = Object.assign({}, self.params, params); 448 | if (!params.subdomains) { 449 | return url; 450 | } 451 | try { 452 | // const cached = await this.isCached(url, metadata, params); 453 | const subdomains = await this.throttled(this.subdomains, 30*1000, url, null, metadata, params, metadata.pool); 454 | if (!context.usedSubdomains) context.usedSubdomains = []; 455 | let sub = subdomains.filter(e => !context.usedSubdomains.includes(e)); 456 | if (sub.length == 0 && subdomains.length > 0) { 457 | sub = [subdomains[0]]; 458 | context.usedSubdomains = []; 459 | } 460 | if (sub.length !== 0) { 461 | const s = sub[0]; 462 | url.set('hostname', s + '.' + url.hostname); 463 | context.usedSubdomains.push(s); 464 | } 465 | } catch (e) { 466 | debug(e); 467 | console.log(e); 468 | return false; 469 | } 470 | return url; 471 | } 472 | }; 473 | return util; 474 | } -------------------------------------------------------------------------------- /proto/url-store/url-store_pb.js: -------------------------------------------------------------------------------- 1 | // source: proto/url-store/url-store.proto 2 | /** 3 | * @fileoverview 4 | * @enhanceable 5 | * @suppress {messageConventions} JS Compiler reports an error if a variable or 6 | * field starts with 'MSG_' and isn't a translatable message. 7 | * @public 8 | */ 9 | // GENERATED CODE -- DO NOT EDIT! 10 | /* eslint-disable */ 11 | // @ts-nocheck 12 | 13 | var jspb = require('google-protobuf'); 14 | var goog = jspb; 15 | var proto = {}; 16 | 17 | goog.exportSymbol('webtor.url_store.CheckReply', null, proto); 18 | goog.exportSymbol('webtor.url_store.CheckRequest', null, proto); 19 | goog.exportSymbol('webtor.url_store.PushReply', null, proto); 20 | goog.exportSymbol('webtor.url_store.PushRequest', null, proto); 21 | /** 22 | * Generated by JsPbCodeGenerator. 23 | * @param {Array=} opt_data Optional initial data array, typically from a 24 | * server response, or constructed directly in Javascript. The array is used 25 | * in place and becomes part of the constructed object. It is not cloned. 26 | * If no data is provided, the constructed object will be empty, but still 27 | * valid. 28 | * @extends {jspb.Message} 29 | * @constructor 30 | */ 31 | proto.webtor.url_store.PushReply = function(opt_data) { 32 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 33 | }; 34 | goog.inherits(proto.webtor.url_store.PushReply, jspb.Message); 35 | if (goog.DEBUG && !COMPILED) { 36 | /** 37 | * @public 38 | * @override 39 | */ 40 | proto.webtor.url_store.PushReply.displayName = 'proto.webtor.url_store.PushReply'; 41 | } 42 | /** 43 | * Generated by JsPbCodeGenerator. 44 | * @param {Array=} opt_data Optional initial data array, typically from a 45 | * server response, or constructed directly in Javascript. The array is used 46 | * in place and becomes part of the constructed object. It is not cloned. 47 | * If no data is provided, the constructed object will be empty, but still 48 | * valid. 49 | * @extends {jspb.Message} 50 | * @constructor 51 | */ 52 | proto.webtor.url_store.PushRequest = function(opt_data) { 53 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 54 | }; 55 | goog.inherits(proto.webtor.url_store.PushRequest, jspb.Message); 56 | if (goog.DEBUG && !COMPILED) { 57 | /** 58 | * @public 59 | * @override 60 | */ 61 | proto.webtor.url_store.PushRequest.displayName = 'proto.webtor.url_store.PushRequest'; 62 | } 63 | /** 64 | * Generated by JsPbCodeGenerator. 65 | * @param {Array=} opt_data Optional initial data array, typically from a 66 | * server response, or constructed directly in Javascript. The array is used 67 | * in place and becomes part of the constructed object. It is not cloned. 68 | * If no data is provided, the constructed object will be empty, but still 69 | * valid. 70 | * @extends {jspb.Message} 71 | * @constructor 72 | */ 73 | proto.webtor.url_store.CheckRequest = function(opt_data) { 74 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 75 | }; 76 | goog.inherits(proto.webtor.url_store.CheckRequest, jspb.Message); 77 | if (goog.DEBUG && !COMPILED) { 78 | /** 79 | * @public 80 | * @override 81 | */ 82 | proto.webtor.url_store.CheckRequest.displayName = 'proto.webtor.url_store.CheckRequest'; 83 | } 84 | /** 85 | * Generated by JsPbCodeGenerator. 86 | * @param {Array=} opt_data Optional initial data array, typically from a 87 | * server response, or constructed directly in Javascript. The array is used 88 | * in place and becomes part of the constructed object. It is not cloned. 89 | * If no data is provided, the constructed object will be empty, but still 90 | * valid. 91 | * @extends {jspb.Message} 92 | * @constructor 93 | */ 94 | proto.webtor.url_store.CheckReply = function(opt_data) { 95 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 96 | }; 97 | goog.inherits(proto.webtor.url_store.CheckReply, jspb.Message); 98 | if (goog.DEBUG && !COMPILED) { 99 | /** 100 | * @public 101 | * @override 102 | */ 103 | proto.webtor.url_store.CheckReply.displayName = 'proto.webtor.url_store.CheckReply'; 104 | } 105 | 106 | 107 | 108 | if (jspb.Message.GENERATE_TO_OBJECT) { 109 | /** 110 | * Creates an object representation of this proto. 111 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 112 | * Optional fields that are not set will be set to undefined. 113 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 114 | * For the list of reserved names please see: 115 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 116 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 117 | * JSPB instance for transitional soy proto support: 118 | * http://goto/soy-param-migration 119 | * @return {!Object} 120 | */ 121 | proto.webtor.url_store.PushReply.prototype.toObject = function(opt_includeInstance) { 122 | return proto.webtor.url_store.PushReply.toObject(opt_includeInstance, this); 123 | }; 124 | 125 | 126 | /** 127 | * Static version of the {@see toObject} method. 128 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 129 | * the JSPB instance for transitional soy proto support: 130 | * http://goto/soy-param-migration 131 | * @param {!proto.webtor.url_store.PushReply} msg The msg instance to transform. 132 | * @return {!Object} 133 | * @suppress {unusedLocalVariables} f is only used for nested messages 134 | */ 135 | proto.webtor.url_store.PushReply.toObject = function(includeInstance, msg) { 136 | var f, obj = { 137 | hash: jspb.Message.getFieldWithDefault(msg, 1, "") 138 | }; 139 | 140 | if (includeInstance) { 141 | obj.$jspbMessageInstance = msg; 142 | } 143 | return obj; 144 | }; 145 | } 146 | 147 | 148 | /** 149 | * Deserializes binary data (in protobuf wire format). 150 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 151 | * @return {!proto.webtor.url_store.PushReply} 152 | */ 153 | proto.webtor.url_store.PushReply.deserializeBinary = function(bytes) { 154 | var reader = new jspb.BinaryReader(bytes); 155 | var msg = new proto.webtor.url_store.PushReply; 156 | return proto.webtor.url_store.PushReply.deserializeBinaryFromReader(msg, reader); 157 | }; 158 | 159 | 160 | /** 161 | * Deserializes binary data (in protobuf wire format) from the 162 | * given reader into the given message object. 163 | * @param {!proto.webtor.url_store.PushReply} msg The message object to deserialize into. 164 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 165 | * @return {!proto.webtor.url_store.PushReply} 166 | */ 167 | proto.webtor.url_store.PushReply.deserializeBinaryFromReader = function(msg, reader) { 168 | while (reader.nextField()) { 169 | if (reader.isEndGroup()) { 170 | break; 171 | } 172 | var field = reader.getFieldNumber(); 173 | switch (field) { 174 | case 1: 175 | var value = /** @type {string} */ (reader.readString()); 176 | msg.setHash(value); 177 | break; 178 | default: 179 | reader.skipField(); 180 | break; 181 | } 182 | } 183 | return msg; 184 | }; 185 | 186 | 187 | /** 188 | * Serializes the message to binary data (in protobuf wire format). 189 | * @return {!Uint8Array} 190 | */ 191 | proto.webtor.url_store.PushReply.prototype.serializeBinary = function() { 192 | var writer = new jspb.BinaryWriter(); 193 | proto.webtor.url_store.PushReply.serializeBinaryToWriter(this, writer); 194 | return writer.getResultBuffer(); 195 | }; 196 | 197 | 198 | /** 199 | * Serializes the given message to binary data (in protobuf wire 200 | * format), writing to the given BinaryWriter. 201 | * @param {!proto.webtor.url_store.PushReply} message 202 | * @param {!jspb.BinaryWriter} writer 203 | * @suppress {unusedLocalVariables} f is only used for nested messages 204 | */ 205 | proto.webtor.url_store.PushReply.serializeBinaryToWriter = function(message, writer) { 206 | var f = undefined; 207 | f = message.getHash(); 208 | if (f.length > 0) { 209 | writer.writeString( 210 | 1, 211 | f 212 | ); 213 | } 214 | }; 215 | 216 | 217 | /** 218 | * optional string hash = 1; 219 | * @return {string} 220 | */ 221 | proto.webtor.url_store.PushReply.prototype.getHash = function() { 222 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 223 | }; 224 | 225 | 226 | /** 227 | * @param {string} value 228 | * @return {!proto.webtor.url_store.PushReply} returns this 229 | */ 230 | proto.webtor.url_store.PushReply.prototype.setHash = function(value) { 231 | return jspb.Message.setProto3StringField(this, 1, value); 232 | }; 233 | 234 | 235 | 236 | 237 | 238 | if (jspb.Message.GENERATE_TO_OBJECT) { 239 | /** 240 | * Creates an object representation of this proto. 241 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 242 | * Optional fields that are not set will be set to undefined. 243 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 244 | * For the list of reserved names please see: 245 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 246 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 247 | * JSPB instance for transitional soy proto support: 248 | * http://goto/soy-param-migration 249 | * @return {!Object} 250 | */ 251 | proto.webtor.url_store.PushRequest.prototype.toObject = function(opt_includeInstance) { 252 | return proto.webtor.url_store.PushRequest.toObject(opt_includeInstance, this); 253 | }; 254 | 255 | 256 | /** 257 | * Static version of the {@see toObject} method. 258 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 259 | * the JSPB instance for transitional soy proto support: 260 | * http://goto/soy-param-migration 261 | * @param {!proto.webtor.url_store.PushRequest} msg The msg instance to transform. 262 | * @return {!Object} 263 | * @suppress {unusedLocalVariables} f is only used for nested messages 264 | */ 265 | proto.webtor.url_store.PushRequest.toObject = function(includeInstance, msg) { 266 | var f, obj = { 267 | url: jspb.Message.getFieldWithDefault(msg, 1, "") 268 | }; 269 | 270 | if (includeInstance) { 271 | obj.$jspbMessageInstance = msg; 272 | } 273 | return obj; 274 | }; 275 | } 276 | 277 | 278 | /** 279 | * Deserializes binary data (in protobuf wire format). 280 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 281 | * @return {!proto.webtor.url_store.PushRequest} 282 | */ 283 | proto.webtor.url_store.PushRequest.deserializeBinary = function(bytes) { 284 | var reader = new jspb.BinaryReader(bytes); 285 | var msg = new proto.webtor.url_store.PushRequest; 286 | return proto.webtor.url_store.PushRequest.deserializeBinaryFromReader(msg, reader); 287 | }; 288 | 289 | 290 | /** 291 | * Deserializes binary data (in protobuf wire format) from the 292 | * given reader into the given message object. 293 | * @param {!proto.webtor.url_store.PushRequest} msg The message object to deserialize into. 294 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 295 | * @return {!proto.webtor.url_store.PushRequest} 296 | */ 297 | proto.webtor.url_store.PushRequest.deserializeBinaryFromReader = function(msg, reader) { 298 | while (reader.nextField()) { 299 | if (reader.isEndGroup()) { 300 | break; 301 | } 302 | var field = reader.getFieldNumber(); 303 | switch (field) { 304 | case 1: 305 | var value = /** @type {string} */ (reader.readString()); 306 | msg.setUrl(value); 307 | break; 308 | default: 309 | reader.skipField(); 310 | break; 311 | } 312 | } 313 | return msg; 314 | }; 315 | 316 | 317 | /** 318 | * Serializes the message to binary data (in protobuf wire format). 319 | * @return {!Uint8Array} 320 | */ 321 | proto.webtor.url_store.PushRequest.prototype.serializeBinary = function() { 322 | var writer = new jspb.BinaryWriter(); 323 | proto.webtor.url_store.PushRequest.serializeBinaryToWriter(this, writer); 324 | return writer.getResultBuffer(); 325 | }; 326 | 327 | 328 | /** 329 | * Serializes the given message to binary data (in protobuf wire 330 | * format), writing to the given BinaryWriter. 331 | * @param {!proto.webtor.url_store.PushRequest} message 332 | * @param {!jspb.BinaryWriter} writer 333 | * @suppress {unusedLocalVariables} f is only used for nested messages 334 | */ 335 | proto.webtor.url_store.PushRequest.serializeBinaryToWriter = function(message, writer) { 336 | var f = undefined; 337 | f = message.getUrl(); 338 | if (f.length > 0) { 339 | writer.writeString( 340 | 1, 341 | f 342 | ); 343 | } 344 | }; 345 | 346 | 347 | /** 348 | * optional string url = 1; 349 | * @return {string} 350 | */ 351 | proto.webtor.url_store.PushRequest.prototype.getUrl = function() { 352 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 353 | }; 354 | 355 | 356 | /** 357 | * @param {string} value 358 | * @return {!proto.webtor.url_store.PushRequest} returns this 359 | */ 360 | proto.webtor.url_store.PushRequest.prototype.setUrl = function(value) { 361 | return jspb.Message.setProto3StringField(this, 1, value); 362 | }; 363 | 364 | 365 | 366 | 367 | 368 | if (jspb.Message.GENERATE_TO_OBJECT) { 369 | /** 370 | * Creates an object representation of this proto. 371 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 372 | * Optional fields that are not set will be set to undefined. 373 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 374 | * For the list of reserved names please see: 375 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 376 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 377 | * JSPB instance for transitional soy proto support: 378 | * http://goto/soy-param-migration 379 | * @return {!Object} 380 | */ 381 | proto.webtor.url_store.CheckRequest.prototype.toObject = function(opt_includeInstance) { 382 | return proto.webtor.url_store.CheckRequest.toObject(opt_includeInstance, this); 383 | }; 384 | 385 | 386 | /** 387 | * Static version of the {@see toObject} method. 388 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 389 | * the JSPB instance for transitional soy proto support: 390 | * http://goto/soy-param-migration 391 | * @param {!proto.webtor.url_store.CheckRequest} msg The msg instance to transform. 392 | * @return {!Object} 393 | * @suppress {unusedLocalVariables} f is only used for nested messages 394 | */ 395 | proto.webtor.url_store.CheckRequest.toObject = function(includeInstance, msg) { 396 | var f, obj = { 397 | hash: jspb.Message.getFieldWithDefault(msg, 1, "") 398 | }; 399 | 400 | if (includeInstance) { 401 | obj.$jspbMessageInstance = msg; 402 | } 403 | return obj; 404 | }; 405 | } 406 | 407 | 408 | /** 409 | * Deserializes binary data (in protobuf wire format). 410 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 411 | * @return {!proto.webtor.url_store.CheckRequest} 412 | */ 413 | proto.webtor.url_store.CheckRequest.deserializeBinary = function(bytes) { 414 | var reader = new jspb.BinaryReader(bytes); 415 | var msg = new proto.webtor.url_store.CheckRequest; 416 | return proto.webtor.url_store.CheckRequest.deserializeBinaryFromReader(msg, reader); 417 | }; 418 | 419 | 420 | /** 421 | * Deserializes binary data (in protobuf wire format) from the 422 | * given reader into the given message object. 423 | * @param {!proto.webtor.url_store.CheckRequest} msg The message object to deserialize into. 424 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 425 | * @return {!proto.webtor.url_store.CheckRequest} 426 | */ 427 | proto.webtor.url_store.CheckRequest.deserializeBinaryFromReader = function(msg, reader) { 428 | while (reader.nextField()) { 429 | if (reader.isEndGroup()) { 430 | break; 431 | } 432 | var field = reader.getFieldNumber(); 433 | switch (field) { 434 | case 1: 435 | var value = /** @type {string} */ (reader.readString()); 436 | msg.setHash(value); 437 | break; 438 | default: 439 | reader.skipField(); 440 | break; 441 | } 442 | } 443 | return msg; 444 | }; 445 | 446 | 447 | /** 448 | * Serializes the message to binary data (in protobuf wire format). 449 | * @return {!Uint8Array} 450 | */ 451 | proto.webtor.url_store.CheckRequest.prototype.serializeBinary = function() { 452 | var writer = new jspb.BinaryWriter(); 453 | proto.webtor.url_store.CheckRequest.serializeBinaryToWriter(this, writer); 454 | return writer.getResultBuffer(); 455 | }; 456 | 457 | 458 | /** 459 | * Serializes the given message to binary data (in protobuf wire 460 | * format), writing to the given BinaryWriter. 461 | * @param {!proto.webtor.url_store.CheckRequest} message 462 | * @param {!jspb.BinaryWriter} writer 463 | * @suppress {unusedLocalVariables} f is only used for nested messages 464 | */ 465 | proto.webtor.url_store.CheckRequest.serializeBinaryToWriter = function(message, writer) { 466 | var f = undefined; 467 | f = message.getHash(); 468 | if (f.length > 0) { 469 | writer.writeString( 470 | 1, 471 | f 472 | ); 473 | } 474 | }; 475 | 476 | 477 | /** 478 | * optional string hash = 1; 479 | * @return {string} 480 | */ 481 | proto.webtor.url_store.CheckRequest.prototype.getHash = function() { 482 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 483 | }; 484 | 485 | 486 | /** 487 | * @param {string} value 488 | * @return {!proto.webtor.url_store.CheckRequest} returns this 489 | */ 490 | proto.webtor.url_store.CheckRequest.prototype.setHash = function(value) { 491 | return jspb.Message.setProto3StringField(this, 1, value); 492 | }; 493 | 494 | 495 | 496 | 497 | 498 | if (jspb.Message.GENERATE_TO_OBJECT) { 499 | /** 500 | * Creates an object representation of this proto. 501 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 502 | * Optional fields that are not set will be set to undefined. 503 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 504 | * For the list of reserved names please see: 505 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 506 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 507 | * JSPB instance for transitional soy proto support: 508 | * http://goto/soy-param-migration 509 | * @return {!Object} 510 | */ 511 | proto.webtor.url_store.CheckReply.prototype.toObject = function(opt_includeInstance) { 512 | return proto.webtor.url_store.CheckReply.toObject(opt_includeInstance, this); 513 | }; 514 | 515 | 516 | /** 517 | * Static version of the {@see toObject} method. 518 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 519 | * the JSPB instance for transitional soy proto support: 520 | * http://goto/soy-param-migration 521 | * @param {!proto.webtor.url_store.CheckReply} msg The msg instance to transform. 522 | * @return {!Object} 523 | * @suppress {unusedLocalVariables} f is only used for nested messages 524 | */ 525 | proto.webtor.url_store.CheckReply.toObject = function(includeInstance, msg) { 526 | var f, obj = { 527 | exists: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) 528 | }; 529 | 530 | if (includeInstance) { 531 | obj.$jspbMessageInstance = msg; 532 | } 533 | return obj; 534 | }; 535 | } 536 | 537 | 538 | /** 539 | * Deserializes binary data (in protobuf wire format). 540 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 541 | * @return {!proto.webtor.url_store.CheckReply} 542 | */ 543 | proto.webtor.url_store.CheckReply.deserializeBinary = function(bytes) { 544 | var reader = new jspb.BinaryReader(bytes); 545 | var msg = new proto.webtor.url_store.CheckReply; 546 | return proto.webtor.url_store.CheckReply.deserializeBinaryFromReader(msg, reader); 547 | }; 548 | 549 | 550 | /** 551 | * Deserializes binary data (in protobuf wire format) from the 552 | * given reader into the given message object. 553 | * @param {!proto.webtor.url_store.CheckReply} msg The message object to deserialize into. 554 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 555 | * @return {!proto.webtor.url_store.CheckReply} 556 | */ 557 | proto.webtor.url_store.CheckReply.deserializeBinaryFromReader = function(msg, reader) { 558 | while (reader.nextField()) { 559 | if (reader.isEndGroup()) { 560 | break; 561 | } 562 | var field = reader.getFieldNumber(); 563 | switch (field) { 564 | case 1: 565 | var value = /** @type {boolean} */ (reader.readBool()); 566 | msg.setExists(value); 567 | break; 568 | default: 569 | reader.skipField(); 570 | break; 571 | } 572 | } 573 | return msg; 574 | }; 575 | 576 | 577 | /** 578 | * Serializes the message to binary data (in protobuf wire format). 579 | * @return {!Uint8Array} 580 | */ 581 | proto.webtor.url_store.CheckReply.prototype.serializeBinary = function() { 582 | var writer = new jspb.BinaryWriter(); 583 | proto.webtor.url_store.CheckReply.serializeBinaryToWriter(this, writer); 584 | return writer.getResultBuffer(); 585 | }; 586 | 587 | 588 | /** 589 | * Serializes the given message to binary data (in protobuf wire 590 | * format), writing to the given BinaryWriter. 591 | * @param {!proto.webtor.url_store.CheckReply} message 592 | * @param {!jspb.BinaryWriter} writer 593 | * @suppress {unusedLocalVariables} f is only used for nested messages 594 | */ 595 | proto.webtor.url_store.CheckReply.serializeBinaryToWriter = function(message, writer) { 596 | var f = undefined; 597 | f = message.getExists(); 598 | if (f) { 599 | writer.writeBool( 600 | 1, 601 | f 602 | ); 603 | } 604 | }; 605 | 606 | 607 | /** 608 | * optional bool exists = 1; 609 | * @return {boolean} 610 | */ 611 | proto.webtor.url_store.CheckReply.prototype.getExists = function() { 612 | return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); 613 | }; 614 | 615 | 616 | /** 617 | * @param {boolean} value 618 | * @return {!proto.webtor.url_store.CheckReply} returns this 619 | */ 620 | proto.webtor.url_store.CheckReply.prototype.setExists = function(value) { 621 | return jspb.Message.setProto3BooleanField(this, 1, value); 622 | }; 623 | 624 | 625 | goog.object.extend(exports, proto); 626 | -------------------------------------------------------------------------------- /proto/abuse-store/abuse-store_pb.js: -------------------------------------------------------------------------------- 1 | // source: proto/abuse-store/abuse-store.proto 2 | /** 3 | * @fileoverview 4 | * @enhanceable 5 | * @suppress {messageConventions} JS Compiler reports an error if a variable or 6 | * field starts with 'MSG_' and isn't a translatable message. 7 | * @public 8 | */ 9 | // GENERATED CODE -- DO NOT EDIT! 10 | /* eslint-disable */ 11 | // @ts-nocheck 12 | 13 | var jspb = require('google-protobuf'); 14 | var goog = jspb; 15 | var proto = {}; 16 | 17 | goog.exportSymbol('CheckReply', null, proto); 18 | goog.exportSymbol('CheckRequest', null, proto); 19 | goog.exportSymbol('PushReply', null, proto); 20 | goog.exportSymbol('PushRequest', null, proto); 21 | goog.exportSymbol('PushRequest.Cause', null, proto); 22 | goog.exportSymbol('PushRequest.Source', null, proto); 23 | /** 24 | * Generated by JsPbCodeGenerator. 25 | * @param {Array=} opt_data Optional initial data array, typically from a 26 | * server response, or constructed directly in Javascript. The array is used 27 | * in place and becomes part of the constructed object. It is not cloned. 28 | * If no data is provided, the constructed object will be empty, but still 29 | * valid. 30 | * @extends {jspb.Message} 31 | * @constructor 32 | */ 33 | proto.PushReply = function(opt_data) { 34 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 35 | }; 36 | goog.inherits(proto.PushReply, jspb.Message); 37 | if (goog.DEBUG && !COMPILED) { 38 | /** 39 | * @public 40 | * @override 41 | */ 42 | proto.PushReply.displayName = 'proto.PushReply'; 43 | } 44 | /** 45 | * Generated by JsPbCodeGenerator. 46 | * @param {Array=} opt_data Optional initial data array, typically from a 47 | * server response, or constructed directly in Javascript. The array is used 48 | * in place and becomes part of the constructed object. It is not cloned. 49 | * If no data is provided, the constructed object will be empty, but still 50 | * valid. 51 | * @extends {jspb.Message} 52 | * @constructor 53 | */ 54 | proto.PushRequest = function(opt_data) { 55 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 56 | }; 57 | goog.inherits(proto.PushRequest, jspb.Message); 58 | if (goog.DEBUG && !COMPILED) { 59 | /** 60 | * @public 61 | * @override 62 | */ 63 | proto.PushRequest.displayName = 'proto.PushRequest'; 64 | } 65 | /** 66 | * Generated by JsPbCodeGenerator. 67 | * @param {Array=} opt_data Optional initial data array, typically from a 68 | * server response, or constructed directly in Javascript. The array is used 69 | * in place and becomes part of the constructed object. It is not cloned. 70 | * If no data is provided, the constructed object will be empty, but still 71 | * valid. 72 | * @extends {jspb.Message} 73 | * @constructor 74 | */ 75 | proto.CheckRequest = function(opt_data) { 76 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 77 | }; 78 | goog.inherits(proto.CheckRequest, jspb.Message); 79 | if (goog.DEBUG && !COMPILED) { 80 | /** 81 | * @public 82 | * @override 83 | */ 84 | proto.CheckRequest.displayName = 'proto.CheckRequest'; 85 | } 86 | /** 87 | * Generated by JsPbCodeGenerator. 88 | * @param {Array=} opt_data Optional initial data array, typically from a 89 | * server response, or constructed directly in Javascript. The array is used 90 | * in place and becomes part of the constructed object. It is not cloned. 91 | * If no data is provided, the constructed object will be empty, but still 92 | * valid. 93 | * @extends {jspb.Message} 94 | * @constructor 95 | */ 96 | proto.CheckReply = function(opt_data) { 97 | jspb.Message.initialize(this, opt_data, 0, -1, null, null); 98 | }; 99 | goog.inherits(proto.CheckReply, jspb.Message); 100 | if (goog.DEBUG && !COMPILED) { 101 | /** 102 | * @public 103 | * @override 104 | */ 105 | proto.CheckReply.displayName = 'proto.CheckReply'; 106 | } 107 | 108 | 109 | 110 | if (jspb.Message.GENERATE_TO_OBJECT) { 111 | /** 112 | * Creates an object representation of this proto. 113 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 114 | * Optional fields that are not set will be set to undefined. 115 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 116 | * For the list of reserved names please see: 117 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 118 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 119 | * JSPB instance for transitional soy proto support: 120 | * http://goto/soy-param-migration 121 | * @return {!Object} 122 | */ 123 | proto.PushReply.prototype.toObject = function(opt_includeInstance) { 124 | return proto.PushReply.toObject(opt_includeInstance, this); 125 | }; 126 | 127 | 128 | /** 129 | * Static version of the {@see toObject} method. 130 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 131 | * the JSPB instance for transitional soy proto support: 132 | * http://goto/soy-param-migration 133 | * @param {!proto.PushReply} msg The msg instance to transform. 134 | * @return {!Object} 135 | * @suppress {unusedLocalVariables} f is only used for nested messages 136 | */ 137 | proto.PushReply.toObject = function(includeInstance, msg) { 138 | var f, obj = { 139 | 140 | }; 141 | 142 | if (includeInstance) { 143 | obj.$jspbMessageInstance = msg; 144 | } 145 | return obj; 146 | }; 147 | } 148 | 149 | 150 | /** 151 | * Deserializes binary data (in protobuf wire format). 152 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 153 | * @return {!proto.PushReply} 154 | */ 155 | proto.PushReply.deserializeBinary = function(bytes) { 156 | var reader = new jspb.BinaryReader(bytes); 157 | var msg = new proto.PushReply; 158 | return proto.PushReply.deserializeBinaryFromReader(msg, reader); 159 | }; 160 | 161 | 162 | /** 163 | * Deserializes binary data (in protobuf wire format) from the 164 | * given reader into the given message object. 165 | * @param {!proto.PushReply} msg The message object to deserialize into. 166 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 167 | * @return {!proto.PushReply} 168 | */ 169 | proto.PushReply.deserializeBinaryFromReader = function(msg, reader) { 170 | while (reader.nextField()) { 171 | if (reader.isEndGroup()) { 172 | break; 173 | } 174 | var field = reader.getFieldNumber(); 175 | switch (field) { 176 | default: 177 | reader.skipField(); 178 | break; 179 | } 180 | } 181 | return msg; 182 | }; 183 | 184 | 185 | /** 186 | * Serializes the message to binary data (in protobuf wire format). 187 | * @return {!Uint8Array} 188 | */ 189 | proto.PushReply.prototype.serializeBinary = function() { 190 | var writer = new jspb.BinaryWriter(); 191 | proto.PushReply.serializeBinaryToWriter(this, writer); 192 | return writer.getResultBuffer(); 193 | }; 194 | 195 | 196 | /** 197 | * Serializes the given message to binary data (in protobuf wire 198 | * format), writing to the given BinaryWriter. 199 | * @param {!proto.PushReply} message 200 | * @param {!jspb.BinaryWriter} writer 201 | * @suppress {unusedLocalVariables} f is only used for nested messages 202 | */ 203 | proto.PushReply.serializeBinaryToWriter = function(message, writer) { 204 | var f = undefined; 205 | }; 206 | 207 | 208 | 209 | 210 | 211 | if (jspb.Message.GENERATE_TO_OBJECT) { 212 | /** 213 | * Creates an object representation of this proto. 214 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 215 | * Optional fields that are not set will be set to undefined. 216 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 217 | * For the list of reserved names please see: 218 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 219 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 220 | * JSPB instance for transitional soy proto support: 221 | * http://goto/soy-param-migration 222 | * @return {!Object} 223 | */ 224 | proto.PushRequest.prototype.toObject = function(opt_includeInstance) { 225 | return proto.PushRequest.toObject(opt_includeInstance, this); 226 | }; 227 | 228 | 229 | /** 230 | * Static version of the {@see toObject} method. 231 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 232 | * the JSPB instance for transitional soy proto support: 233 | * http://goto/soy-param-migration 234 | * @param {!proto.PushRequest} msg The msg instance to transform. 235 | * @return {!Object} 236 | * @suppress {unusedLocalVariables} f is only used for nested messages 237 | */ 238 | proto.PushRequest.toObject = function(includeInstance, msg) { 239 | var f, obj = { 240 | noticeId: jspb.Message.getFieldWithDefault(msg, 1, ""), 241 | infohash: jspb.Message.getFieldWithDefault(msg, 2, ""), 242 | filename: jspb.Message.getFieldWithDefault(msg, 3, ""), 243 | work: jspb.Message.getFieldWithDefault(msg, 4, ""), 244 | startedAt: jspb.Message.getFieldWithDefault(msg, 5, 0), 245 | email: jspb.Message.getFieldWithDefault(msg, 6, ""), 246 | description: jspb.Message.getFieldWithDefault(msg, 7, ""), 247 | subject: jspb.Message.getFieldWithDefault(msg, 8, ""), 248 | cause: jspb.Message.getFieldWithDefault(msg, 9, 0), 249 | source: jspb.Message.getFieldWithDefault(msg, 10, 0) 250 | }; 251 | 252 | if (includeInstance) { 253 | obj.$jspbMessageInstance = msg; 254 | } 255 | return obj; 256 | }; 257 | } 258 | 259 | 260 | /** 261 | * Deserializes binary data (in protobuf wire format). 262 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 263 | * @return {!proto.PushRequest} 264 | */ 265 | proto.PushRequest.deserializeBinary = function(bytes) { 266 | var reader = new jspb.BinaryReader(bytes); 267 | var msg = new proto.PushRequest; 268 | return proto.PushRequest.deserializeBinaryFromReader(msg, reader); 269 | }; 270 | 271 | 272 | /** 273 | * Deserializes binary data (in protobuf wire format) from the 274 | * given reader into the given message object. 275 | * @param {!proto.PushRequest} msg The message object to deserialize into. 276 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 277 | * @return {!proto.PushRequest} 278 | */ 279 | proto.PushRequest.deserializeBinaryFromReader = function(msg, reader) { 280 | while (reader.nextField()) { 281 | if (reader.isEndGroup()) { 282 | break; 283 | } 284 | var field = reader.getFieldNumber(); 285 | switch (field) { 286 | case 1: 287 | var value = /** @type {string} */ (reader.readString()); 288 | msg.setNoticeId(value); 289 | break; 290 | case 2: 291 | var value = /** @type {string} */ (reader.readString()); 292 | msg.setInfohash(value); 293 | break; 294 | case 3: 295 | var value = /** @type {string} */ (reader.readString()); 296 | msg.setFilename(value); 297 | break; 298 | case 4: 299 | var value = /** @type {string} */ (reader.readString()); 300 | msg.setWork(value); 301 | break; 302 | case 5: 303 | var value = /** @type {number} */ (reader.readInt64()); 304 | msg.setStartedAt(value); 305 | break; 306 | case 6: 307 | var value = /** @type {string} */ (reader.readString()); 308 | msg.setEmail(value); 309 | break; 310 | case 7: 311 | var value = /** @type {string} */ (reader.readString()); 312 | msg.setDescription(value); 313 | break; 314 | case 8: 315 | var value = /** @type {string} */ (reader.readString()); 316 | msg.setSubject(value); 317 | break; 318 | case 9: 319 | var value = /** @type {!proto.PushRequest.Cause} */ (reader.readEnum()); 320 | msg.setCause(value); 321 | break; 322 | case 10: 323 | var value = /** @type {!proto.PushRequest.Source} */ (reader.readEnum()); 324 | msg.setSource(value); 325 | break; 326 | default: 327 | reader.skipField(); 328 | break; 329 | } 330 | } 331 | return msg; 332 | }; 333 | 334 | 335 | /** 336 | * Serializes the message to binary data (in protobuf wire format). 337 | * @return {!Uint8Array} 338 | */ 339 | proto.PushRequest.prototype.serializeBinary = function() { 340 | var writer = new jspb.BinaryWriter(); 341 | proto.PushRequest.serializeBinaryToWriter(this, writer); 342 | return writer.getResultBuffer(); 343 | }; 344 | 345 | 346 | /** 347 | * Serializes the given message to binary data (in protobuf wire 348 | * format), writing to the given BinaryWriter. 349 | * @param {!proto.PushRequest} message 350 | * @param {!jspb.BinaryWriter} writer 351 | * @suppress {unusedLocalVariables} f is only used for nested messages 352 | */ 353 | proto.PushRequest.serializeBinaryToWriter = function(message, writer) { 354 | var f = undefined; 355 | f = message.getNoticeId(); 356 | if (f.length > 0) { 357 | writer.writeString( 358 | 1, 359 | f 360 | ); 361 | } 362 | f = message.getInfohash(); 363 | if (f.length > 0) { 364 | writer.writeString( 365 | 2, 366 | f 367 | ); 368 | } 369 | f = message.getFilename(); 370 | if (f.length > 0) { 371 | writer.writeString( 372 | 3, 373 | f 374 | ); 375 | } 376 | f = message.getWork(); 377 | if (f.length > 0) { 378 | writer.writeString( 379 | 4, 380 | f 381 | ); 382 | } 383 | f = message.getStartedAt(); 384 | if (f !== 0) { 385 | writer.writeInt64( 386 | 5, 387 | f 388 | ); 389 | } 390 | f = message.getEmail(); 391 | if (f.length > 0) { 392 | writer.writeString( 393 | 6, 394 | f 395 | ); 396 | } 397 | f = message.getDescription(); 398 | if (f.length > 0) { 399 | writer.writeString( 400 | 7, 401 | f 402 | ); 403 | } 404 | f = message.getSubject(); 405 | if (f.length > 0) { 406 | writer.writeString( 407 | 8, 408 | f 409 | ); 410 | } 411 | f = message.getCause(); 412 | if (f !== 0.0) { 413 | writer.writeEnum( 414 | 9, 415 | f 416 | ); 417 | } 418 | f = message.getSource(); 419 | if (f !== 0.0) { 420 | writer.writeEnum( 421 | 10, 422 | f 423 | ); 424 | } 425 | }; 426 | 427 | 428 | /** 429 | * @enum {number} 430 | */ 431 | proto.PushRequest.Cause = { 432 | ILLEGAL_CONTENT: 0, 433 | MALWARE: 1, 434 | APP_ERROR: 2, 435 | QUESTION: 3 436 | }; 437 | 438 | /** 439 | * @enum {number} 440 | */ 441 | proto.PushRequest.Source = { 442 | MAIL: 0, 443 | FORM: 1 444 | }; 445 | 446 | /** 447 | * optional string notice_id = 1; 448 | * @return {string} 449 | */ 450 | proto.PushRequest.prototype.getNoticeId = function() { 451 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 452 | }; 453 | 454 | 455 | /** 456 | * @param {string} value 457 | * @return {!proto.PushRequest} returns this 458 | */ 459 | proto.PushRequest.prototype.setNoticeId = function(value) { 460 | return jspb.Message.setProto3StringField(this, 1, value); 461 | }; 462 | 463 | 464 | /** 465 | * optional string infohash = 2; 466 | * @return {string} 467 | */ 468 | proto.PushRequest.prototype.getInfohash = function() { 469 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); 470 | }; 471 | 472 | 473 | /** 474 | * @param {string} value 475 | * @return {!proto.PushRequest} returns this 476 | */ 477 | proto.PushRequest.prototype.setInfohash = function(value) { 478 | return jspb.Message.setProto3StringField(this, 2, value); 479 | }; 480 | 481 | 482 | /** 483 | * optional string filename = 3; 484 | * @return {string} 485 | */ 486 | proto.PushRequest.prototype.getFilename = function() { 487 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); 488 | }; 489 | 490 | 491 | /** 492 | * @param {string} value 493 | * @return {!proto.PushRequest} returns this 494 | */ 495 | proto.PushRequest.prototype.setFilename = function(value) { 496 | return jspb.Message.setProto3StringField(this, 3, value); 497 | }; 498 | 499 | 500 | /** 501 | * optional string work = 4; 502 | * @return {string} 503 | */ 504 | proto.PushRequest.prototype.getWork = function() { 505 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); 506 | }; 507 | 508 | 509 | /** 510 | * @param {string} value 511 | * @return {!proto.PushRequest} returns this 512 | */ 513 | proto.PushRequest.prototype.setWork = function(value) { 514 | return jspb.Message.setProto3StringField(this, 4, value); 515 | }; 516 | 517 | 518 | /** 519 | * optional int64 started_at = 5; 520 | * @return {number} 521 | */ 522 | proto.PushRequest.prototype.getStartedAt = function() { 523 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); 524 | }; 525 | 526 | 527 | /** 528 | * @param {number} value 529 | * @return {!proto.PushRequest} returns this 530 | */ 531 | proto.PushRequest.prototype.setStartedAt = function(value) { 532 | return jspb.Message.setProto3IntField(this, 5, value); 533 | }; 534 | 535 | 536 | /** 537 | * optional string email = 6; 538 | * @return {string} 539 | */ 540 | proto.PushRequest.prototype.getEmail = function() { 541 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); 542 | }; 543 | 544 | 545 | /** 546 | * @param {string} value 547 | * @return {!proto.PushRequest} returns this 548 | */ 549 | proto.PushRequest.prototype.setEmail = function(value) { 550 | return jspb.Message.setProto3StringField(this, 6, value); 551 | }; 552 | 553 | 554 | /** 555 | * optional string description = 7; 556 | * @return {string} 557 | */ 558 | proto.PushRequest.prototype.getDescription = function() { 559 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); 560 | }; 561 | 562 | 563 | /** 564 | * @param {string} value 565 | * @return {!proto.PushRequest} returns this 566 | */ 567 | proto.PushRequest.prototype.setDescription = function(value) { 568 | return jspb.Message.setProto3StringField(this, 7, value); 569 | }; 570 | 571 | 572 | /** 573 | * optional string subject = 8; 574 | * @return {string} 575 | */ 576 | proto.PushRequest.prototype.getSubject = function() { 577 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 8, "")); 578 | }; 579 | 580 | 581 | /** 582 | * @param {string} value 583 | * @return {!proto.PushRequest} returns this 584 | */ 585 | proto.PushRequest.prototype.setSubject = function(value) { 586 | return jspb.Message.setProto3StringField(this, 8, value); 587 | }; 588 | 589 | 590 | /** 591 | * optional Cause cause = 9; 592 | * @return {!proto.PushRequest.Cause} 593 | */ 594 | proto.PushRequest.prototype.getCause = function() { 595 | return /** @type {!proto.PushRequest.Cause} */ (jspb.Message.getFieldWithDefault(this, 9, 0)); 596 | }; 597 | 598 | 599 | /** 600 | * @param {!proto.PushRequest.Cause} value 601 | * @return {!proto.PushRequest} returns this 602 | */ 603 | proto.PushRequest.prototype.setCause = function(value) { 604 | return jspb.Message.setProto3EnumField(this, 9, value); 605 | }; 606 | 607 | 608 | /** 609 | * optional Source source = 10; 610 | * @return {!proto.PushRequest.Source} 611 | */ 612 | proto.PushRequest.prototype.getSource = function() { 613 | return /** @type {!proto.PushRequest.Source} */ (jspb.Message.getFieldWithDefault(this, 10, 0)); 614 | }; 615 | 616 | 617 | /** 618 | * @param {!proto.PushRequest.Source} value 619 | * @return {!proto.PushRequest} returns this 620 | */ 621 | proto.PushRequest.prototype.setSource = function(value) { 622 | return jspb.Message.setProto3EnumField(this, 10, value); 623 | }; 624 | 625 | 626 | 627 | 628 | 629 | if (jspb.Message.GENERATE_TO_OBJECT) { 630 | /** 631 | * Creates an object representation of this proto. 632 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 633 | * Optional fields that are not set will be set to undefined. 634 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 635 | * For the list of reserved names please see: 636 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 637 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 638 | * JSPB instance for transitional soy proto support: 639 | * http://goto/soy-param-migration 640 | * @return {!Object} 641 | */ 642 | proto.CheckRequest.prototype.toObject = function(opt_includeInstance) { 643 | return proto.CheckRequest.toObject(opt_includeInstance, this); 644 | }; 645 | 646 | 647 | /** 648 | * Static version of the {@see toObject} method. 649 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 650 | * the JSPB instance for transitional soy proto support: 651 | * http://goto/soy-param-migration 652 | * @param {!proto.CheckRequest} msg The msg instance to transform. 653 | * @return {!Object} 654 | * @suppress {unusedLocalVariables} f is only used for nested messages 655 | */ 656 | proto.CheckRequest.toObject = function(includeInstance, msg) { 657 | var f, obj = { 658 | infohash: jspb.Message.getFieldWithDefault(msg, 1, "") 659 | }; 660 | 661 | if (includeInstance) { 662 | obj.$jspbMessageInstance = msg; 663 | } 664 | return obj; 665 | }; 666 | } 667 | 668 | 669 | /** 670 | * Deserializes binary data (in protobuf wire format). 671 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 672 | * @return {!proto.CheckRequest} 673 | */ 674 | proto.CheckRequest.deserializeBinary = function(bytes) { 675 | var reader = new jspb.BinaryReader(bytes); 676 | var msg = new proto.CheckRequest; 677 | return proto.CheckRequest.deserializeBinaryFromReader(msg, reader); 678 | }; 679 | 680 | 681 | /** 682 | * Deserializes binary data (in protobuf wire format) from the 683 | * given reader into the given message object. 684 | * @param {!proto.CheckRequest} msg The message object to deserialize into. 685 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 686 | * @return {!proto.CheckRequest} 687 | */ 688 | proto.CheckRequest.deserializeBinaryFromReader = function(msg, reader) { 689 | while (reader.nextField()) { 690 | if (reader.isEndGroup()) { 691 | break; 692 | } 693 | var field = reader.getFieldNumber(); 694 | switch (field) { 695 | case 1: 696 | var value = /** @type {string} */ (reader.readString()); 697 | msg.setInfohash(value); 698 | break; 699 | default: 700 | reader.skipField(); 701 | break; 702 | } 703 | } 704 | return msg; 705 | }; 706 | 707 | 708 | /** 709 | * Serializes the message to binary data (in protobuf wire format). 710 | * @return {!Uint8Array} 711 | */ 712 | proto.CheckRequest.prototype.serializeBinary = function() { 713 | var writer = new jspb.BinaryWriter(); 714 | proto.CheckRequest.serializeBinaryToWriter(this, writer); 715 | return writer.getResultBuffer(); 716 | }; 717 | 718 | 719 | /** 720 | * Serializes the given message to binary data (in protobuf wire 721 | * format), writing to the given BinaryWriter. 722 | * @param {!proto.CheckRequest} message 723 | * @param {!jspb.BinaryWriter} writer 724 | * @suppress {unusedLocalVariables} f is only used for nested messages 725 | */ 726 | proto.CheckRequest.serializeBinaryToWriter = function(message, writer) { 727 | var f = undefined; 728 | f = message.getInfohash(); 729 | if (f.length > 0) { 730 | writer.writeString( 731 | 1, 732 | f 733 | ); 734 | } 735 | }; 736 | 737 | 738 | /** 739 | * optional string infohash = 1; 740 | * @return {string} 741 | */ 742 | proto.CheckRequest.prototype.getInfohash = function() { 743 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); 744 | }; 745 | 746 | 747 | /** 748 | * @param {string} value 749 | * @return {!proto.CheckRequest} returns this 750 | */ 751 | proto.CheckRequest.prototype.setInfohash = function(value) { 752 | return jspb.Message.setProto3StringField(this, 1, value); 753 | }; 754 | 755 | 756 | 757 | 758 | 759 | if (jspb.Message.GENERATE_TO_OBJECT) { 760 | /** 761 | * Creates an object representation of this proto. 762 | * Field names that are reserved in JavaScript and will be renamed to pb_name. 763 | * Optional fields that are not set will be set to undefined. 764 | * To access a reserved field use, foo.pb_, eg, foo.pb_default. 765 | * For the list of reserved names please see: 766 | * net/proto2/compiler/js/internal/generator.cc#kKeyword. 767 | * @param {boolean=} opt_includeInstance Deprecated. whether to include the 768 | * JSPB instance for transitional soy proto support: 769 | * http://goto/soy-param-migration 770 | * @return {!Object} 771 | */ 772 | proto.CheckReply.prototype.toObject = function(opt_includeInstance) { 773 | return proto.CheckReply.toObject(opt_includeInstance, this); 774 | }; 775 | 776 | 777 | /** 778 | * Static version of the {@see toObject} method. 779 | * @param {boolean|undefined} includeInstance Deprecated. Whether to include 780 | * the JSPB instance for transitional soy proto support: 781 | * http://goto/soy-param-migration 782 | * @param {!proto.CheckReply} msg The msg instance to transform. 783 | * @return {!Object} 784 | * @suppress {unusedLocalVariables} f is only used for nested messages 785 | */ 786 | proto.CheckReply.toObject = function(includeInstance, msg) { 787 | var f, obj = { 788 | exists: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) 789 | }; 790 | 791 | if (includeInstance) { 792 | obj.$jspbMessageInstance = msg; 793 | } 794 | return obj; 795 | }; 796 | } 797 | 798 | 799 | /** 800 | * Deserializes binary data (in protobuf wire format). 801 | * @param {jspb.ByteSource} bytes The bytes to deserialize. 802 | * @return {!proto.CheckReply} 803 | */ 804 | proto.CheckReply.deserializeBinary = function(bytes) { 805 | var reader = new jspb.BinaryReader(bytes); 806 | var msg = new proto.CheckReply; 807 | return proto.CheckReply.deserializeBinaryFromReader(msg, reader); 808 | }; 809 | 810 | 811 | /** 812 | * Deserializes binary data (in protobuf wire format) from the 813 | * given reader into the given message object. 814 | * @param {!proto.CheckReply} msg The message object to deserialize into. 815 | * @param {!jspb.BinaryReader} reader The BinaryReader to use. 816 | * @return {!proto.CheckReply} 817 | */ 818 | proto.CheckReply.deserializeBinaryFromReader = function(msg, reader) { 819 | while (reader.nextField()) { 820 | if (reader.isEndGroup()) { 821 | break; 822 | } 823 | var field = reader.getFieldNumber(); 824 | switch (field) { 825 | case 1: 826 | var value = /** @type {boolean} */ (reader.readBool()); 827 | msg.setExists(value); 828 | break; 829 | default: 830 | reader.skipField(); 831 | break; 832 | } 833 | } 834 | return msg; 835 | }; 836 | 837 | 838 | /** 839 | * Serializes the message to binary data (in protobuf wire format). 840 | * @return {!Uint8Array} 841 | */ 842 | proto.CheckReply.prototype.serializeBinary = function() { 843 | var writer = new jspb.BinaryWriter(); 844 | proto.CheckReply.serializeBinaryToWriter(this, writer); 845 | return writer.getResultBuffer(); 846 | }; 847 | 848 | 849 | /** 850 | * Serializes the given message to binary data (in protobuf wire 851 | * format), writing to the given BinaryWriter. 852 | * @param {!proto.CheckReply} message 853 | * @param {!jspb.BinaryWriter} writer 854 | * @suppress {unusedLocalVariables} f is only used for nested messages 855 | */ 856 | proto.CheckReply.serializeBinaryToWriter = function(message, writer) { 857 | var f = undefined; 858 | f = message.getExists(); 859 | if (f) { 860 | writer.writeBool( 861 | 1, 862 | f 863 | ); 864 | } 865 | }; 866 | 867 | 868 | /** 869 | * optional bool exists = 1; 870 | * @return {boolean} 871 | */ 872 | proto.CheckReply.prototype.getExists = function() { 873 | return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); 874 | }; 875 | 876 | 877 | /** 878 | * @param {boolean} value 879 | * @return {!proto.CheckReply} returns this 880 | */ 881 | proto.CheckReply.prototype.setExists = function(value) { 882 | return jspb.Message.setProto3BooleanField(this, 1, value); 883 | }; 884 | 885 | 886 | goog.object.extend(exports, proto); 887 | --------------------------------------------------------------------------------