Use signed rlog URLs for shared rides (#20)
parent
811cb2cc53
commit
87b77f3a57
|
@ -4,7 +4,7 @@
|
|||
"private": true,
|
||||
"homepage": "https://community.comma.ai/cabana",
|
||||
"dependencies": {
|
||||
"@commaai/comma-api": "^1.1.4",
|
||||
"@commaai/comma-api": "1.1.6",
|
||||
"@commaai/hls.js": "^0.12.2",
|
||||
"@commaai/log_reader": "^0.3.1",
|
||||
"@commaai/my-comma-auth": "^1.1.0",
|
||||
|
|
|
@ -6,7 +6,12 @@ import { createWriteStream } from "streamsaver";
|
|||
import Panda from "@commaai/pandajs";
|
||||
import CommaAuth from "@commaai/my-comma-auth";
|
||||
import { raw as RawDataApi, drives as DrivesApi } from "@commaai/comma-api";
|
||||
import { USE_UNLOGGER, PART_SEGMENT_LENGTH, STREAMING_WINDOW } from "./config";
|
||||
import {
|
||||
USE_UNLOGGER,
|
||||
PART_SEGMENT_LENGTH,
|
||||
STREAMING_WINDOW,
|
||||
GITHUB_AUTH_TOKEN_KEY
|
||||
} from "./config";
|
||||
import * as GithubAuth from "./api/github-auth";
|
||||
|
||||
import DBC from "./models/can/dbc";
|
||||
|
@ -27,6 +32,7 @@ import OpenDbc from "./api/OpenDbc";
|
|||
import UnloggerClient from "./api/unlogger";
|
||||
import * as ObjectUtils from "./utils/object";
|
||||
import { hash } from "./utils/string";
|
||||
import { modifyQueryParameters } from "./utils/url";
|
||||
|
||||
const RLogDownloader = require("./workers/rlog-downloader.worker.js");
|
||||
const LogCSVDownloader = require("./workers/dbc-csv-downloader.worker.js");
|
||||
|
@ -80,7 +86,9 @@ export default class CanExplorer extends Component {
|
|||
pandaNoDeviceSelected: false,
|
||||
live: false,
|
||||
isGithubAuthenticated:
|
||||
props.githubAuthToken !== null && props.githubAuthToken !== undefined
|
||||
props.githubAuthToken !== null && props.githubAuthToken !== undefined,
|
||||
shareUrl: null,
|
||||
logUrls: null
|
||||
};
|
||||
|
||||
this.openDbcClient = new OpenDbc(props.githubAuthToken);
|
||||
|
@ -126,9 +134,13 @@ export default class CanExplorer extends Component {
|
|||
componentWillMount() {
|
||||
const { dongleId, name } = this.props;
|
||||
if (CommaAuth.isAuthenticated() && !name) {
|
||||
// TODO link to explorer
|
||||
this.showOnboarding();
|
||||
} else if (this.props.max && this.props.url) {
|
||||
} else if (
|
||||
this.props.max &&
|
||||
this.props.url &&
|
||||
!this.props.exp &&
|
||||
!this.props.sig
|
||||
) {
|
||||
// probably the demo!
|
||||
const { max, url } = this.props;
|
||||
const startTime = Moment(name, "YYYY-MM-DD--H-m-s");
|
||||
|
@ -148,7 +160,8 @@ export default class CanExplorer extends Component {
|
|||
);
|
||||
} else if (dongleId && name) {
|
||||
const routeName = dongleId + "|" + name;
|
||||
let urlPromise;
|
||||
let urlPromise, logUrlsPromise;
|
||||
|
||||
if (this.props.url) {
|
||||
urlPromise = Promise.resolve(this.props.url);
|
||||
} else {
|
||||
|
@ -156,7 +169,16 @@ export default class CanExplorer extends Component {
|
|||
return route.url;
|
||||
});
|
||||
}
|
||||
Promise.all([urlPromise, RawDataApi.getLogUrls(routeName)])
|
||||
|
||||
if (this.props.sig && this.props.exp) {
|
||||
logUrlsPromise = RawDataApi.getLogUrls(routeName, {
|
||||
sig: this.props.sig,
|
||||
exp: this.props.exp
|
||||
});
|
||||
} else {
|
||||
logUrlsPromise = RawDataApi.getLogUrls(routeName);
|
||||
}
|
||||
Promise.all([urlPromise, logUrlsPromise])
|
||||
.then(initData => {
|
||||
let [url, logUrls] = initData;
|
||||
const newState = {
|
||||
|
@ -169,9 +191,24 @@ export default class CanExplorer extends Component {
|
|||
currentParts: [
|
||||
0,
|
||||
Math.min(logUrls.length - 1, PART_SEGMENT_LENGTH - 1)
|
||||
]
|
||||
],
|
||||
logUrls
|
||||
};
|
||||
this.setState(newState, this.initCanData);
|
||||
|
||||
DrivesApi.getShareSignature(routeName).then(shareSignature =>
|
||||
this.setState({
|
||||
shareUrl: modifyQueryParameters({
|
||||
add: {
|
||||
exp: shareSignature.exp,
|
||||
sig: shareSignature.sig,
|
||||
max: logUrls.length - 1,
|
||||
url
|
||||
},
|
||||
remove: [GITHUB_AUTH_TOKEN_KEY]
|
||||
})
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
|
@ -519,7 +556,8 @@ export default class CanExplorer extends Component {
|
|||
|
||||
// so that we don't try to read metadata about it...
|
||||
isDemo: this.props.isDemo,
|
||||
isShare: this.props.isShare,
|
||||
isLegacyShare: this.props.isLegacyShare,
|
||||
logUrls: this.state.logUrls,
|
||||
|
||||
// data that is used
|
||||
dbcText: dbc.text(),
|
||||
|
@ -974,6 +1012,7 @@ export default class CanExplorer extends Component {
|
|||
route={this.state.route}
|
||||
seekTime={this.state.seekTime}
|
||||
seekIndex={this.state.seekIndex}
|
||||
shareUrl={this.state.shareUrl}
|
||||
maxByteStateChangeCount={this.state.maxByteStateChangeCount}
|
||||
isDemo={this.props.isDemo}
|
||||
live={this.state.live}
|
||||
|
|
|
@ -15,28 +15,9 @@ function ensureInit() {
|
|||
return initPromise;
|
||||
}
|
||||
|
||||
export async function getLogURLList(routeName) {
|
||||
if (urlStore[routeName]) {
|
||||
return urlStore[routeName];
|
||||
}
|
||||
await ensureInit();
|
||||
|
||||
var data = await RawDataApi.getLogUrls(routeName);
|
||||
|
||||
urlStore[routeName] = data;
|
||||
|
||||
setTimeout(function() {
|
||||
delete urlStore[routeName];
|
||||
}, 1000 * 60 * 45); // expires in 1h, lets reset in 45m
|
||||
|
||||
return urlStore[routeName];
|
||||
}
|
||||
|
||||
export async function getLogPart(routeName, part) {
|
||||
export async function getLogPart(logUrl) {
|
||||
return new Promise(async function(resolve, reject) {
|
||||
var logUrls = await getLogURLList(routeName);
|
||||
|
||||
request(logUrls[part], function(err, res) {
|
||||
request(logUrl, function(err, res) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ import cx from "classnames";
|
|||
import PropTypes from "prop-types";
|
||||
import Clipboard from "clipboard";
|
||||
|
||||
import { modifyQueryParameters } from "../utils/url";
|
||||
import MessageBytes from "./MessageBytes";
|
||||
import { GITHUB_AUTH_TOKEN_KEY } from "../config";
|
||||
const { ckmeans } = require("simple-statistics");
|
||||
|
||||
export default class Meta extends Component {
|
||||
|
@ -340,17 +338,6 @@ export default class Meta extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
shareUrl() {
|
||||
const add = {
|
||||
max: this.props.route.proclog,
|
||||
url: this.props.route.url
|
||||
};
|
||||
const remove = [GITHUB_AUTH_TOKEN_KEY]; // don't share github access
|
||||
const shareUrl = modifyQueryParameters({ add, remove });
|
||||
|
||||
return shareUrl;
|
||||
}
|
||||
|
||||
saveable() {
|
||||
try {
|
||||
// eslint-disable-next-line
|
||||
|
@ -386,16 +373,16 @@ export default class Meta extends Component {
|
|||
<button onClick={this.props.saveLog}>Save Log</button>
|
||||
</div>
|
||||
)}
|
||||
{this.props.route ? (
|
||||
{this.props.shareUrl ? (
|
||||
<div
|
||||
className="cabana-meta-header-action special-wide"
|
||||
data-clipboard-text={this.shareUrl()}
|
||||
data-clipboard-text={this.props.shareUrl}
|
||||
data-clipboard-action="copy"
|
||||
ref={ref => (ref ? new Clipboard(ref) : null)}
|
||||
>
|
||||
<a
|
||||
className="button"
|
||||
href={this.shareUrl()}
|
||||
href={this.props.shareUrl}
|
||||
onClick={e => e.preventDefault()}
|
||||
>
|
||||
Copy Share Link
|
||||
|
|
14
src/index.js
14
src/index.js
|
@ -29,14 +29,24 @@ if (routeFullName) {
|
|||
persistedDbc = fetchPersistedDbc(routeFullName);
|
||||
|
||||
let max = getUrlParameter("max"),
|
||||
url = getUrlParameter("url");
|
||||
url = getUrlParameter("url"),
|
||||
exp = getUrlParameter("exp"),
|
||||
sig = getUrlParameter("sig");
|
||||
|
||||
if (max) {
|
||||
props.max = Number(max);
|
||||
}
|
||||
if (url) {
|
||||
props.url = url;
|
||||
}
|
||||
props.isShare = max && url;
|
||||
if (exp) {
|
||||
props.exp = exp;
|
||||
}
|
||||
if (sig) {
|
||||
props.sig = sig;
|
||||
}
|
||||
props.isLegacyShare = max && url && !exp && !sig;
|
||||
props.isShare = max && url && exp && sig;
|
||||
} else if (getUrlParameter("demo")) {
|
||||
props.max = 12;
|
||||
props.url =
|
||||
|
|
|
@ -16,7 +16,7 @@ export function getUrlParameter(name) {
|
|||
: decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
export function modifyQueryParameters({ add, remove }) {
|
||||
export function modifyQueryParameters({ add, remove = [] }) {
|
||||
var regex = new RegExp("[\\?&]([^&#]+)=([^&#]*)");
|
||||
var results = regex.exec(location.search);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import LogStream from "@commaai/log_reader";
|
|||
import { timeout } from "thyming";
|
||||
import { partial } from "ap";
|
||||
|
||||
import { getLogPart, getLogURLList } from "../api/rlog";
|
||||
import { getLogPart } from "../api/rlog";
|
||||
import DbcUtils from "../utils/dbc";
|
||||
import DBC from "../models/can/dbc";
|
||||
import { addressForName } from "../models/can/logSignals";
|
||||
|
@ -24,12 +24,13 @@ function CacheEntry(options) {
|
|||
options = options || {};
|
||||
this.options = options;
|
||||
|
||||
let { route, part, dbc } = options;
|
||||
let { route, part, dbc, logUrls } = options;
|
||||
|
||||
this.messages = {};
|
||||
this.route = route;
|
||||
this.part = part;
|
||||
this.dbc = dbc;
|
||||
this.logUrls = logUrls;
|
||||
this.sendBatch = partial(sendBatch, this);
|
||||
|
||||
// load in the data!
|
||||
|
@ -71,9 +72,10 @@ function sendBatch(entry) {
|
|||
async function loadData(entry) {
|
||||
var url = null;
|
||||
|
||||
if (!entry.options.isDemo && !entry.options.isShare) {
|
||||
url = (await getLogURLList(entry.route))[entry.part];
|
||||
if (!entry.options.isDemo && !entry.options.isLegacyShare) {
|
||||
url = entry.logUrls[entry.part];
|
||||
}
|
||||
|
||||
if (!url || url.indexOf(".7z") !== -1) {
|
||||
// this is a shit log we can't read...
|
||||
var data = await loadCanPart(
|
||||
|
@ -88,7 +90,7 @@ async function loadData(entry) {
|
|||
|
||||
return self.postMessage(data);
|
||||
}
|
||||
var res = await getLogPart(entry.route, entry.part);
|
||||
var res = await getLogPart(entry.logUrls[entry.part]);
|
||||
var logReader = new LogStream(res);
|
||||
|
||||
entry.ended = false;
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -17,20 +17,20 @@
|
|||
lodash "^4.2.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@commaai/comma-api@^1.0.0":
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.0.12.tgz#aa2be678dd0cdcf5102602e011051eda354853d6"
|
||||
integrity sha512-AWwKaQzgQt6oyOP0lvMqy5/7rMQbKIVwTYX5MJnBFOVOgHrGmzxhPk8Bsi+5GpSA1qSFbnzoMvQ95QFC5teJhw==
|
||||
"@commaai/comma-api@1.1.6":
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.6.tgz#be486443a8d8843c74a811cdd406b85694b5d526"
|
||||
integrity sha512-LWglx5+GiQN4uhdBUjTJ3hsHxy0/tFVwZrIFKLSwwFyclQWizriHOE4IxKkGLudyQ/KgOL+bLljA+z/huEXW4w==
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
config-request "^0.5.1"
|
||||
joi-browser "^13.4.0"
|
||||
querystringify "^2.1.1"
|
||||
|
||||
"@commaai/comma-api@^1.1.4":
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.4.tgz#75f727bfa43f6f446a341d1f9154f15334cfb79e"
|
||||
integrity sha512-S25QY2OwO1aO5HKtvJQUnCwDsfBhgj7+SANZG99kHvxfFxOwWzT/GcV7G/xEtEJ06OsJ+Ih8XoUFm7IxNc1bwA==
|
||||
"@commaai/comma-api@^1.0.0":
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.0.12.tgz#aa2be678dd0cdcf5102602e011051eda354853d6"
|
||||
integrity sha512-AWwKaQzgQt6oyOP0lvMqy5/7rMQbKIVwTYX5MJnBFOVOgHrGmzxhPk8Bsi+5GpSA1qSFbnzoMvQ95QFC5teJhw==
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
config-request "^0.5.1"
|
||||
|
|
Loading…
Reference in New Issue