Subscribe to peers/files/trackers/pieces
This commit is contained in:
parent
9d1fa85582
commit
409238ba58
|
@ -9,7 +9,7 @@
|
||||||
.torrent {
|
.torrent {
|
||||||
&.paused {
|
&.paused {
|
||||||
color: $gray-dark;
|
color: $gray-dark;
|
||||||
background: $gray-lighter;
|
background-color: $gray-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.idle {
|
&.idle {
|
||||||
|
@ -25,12 +25,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.pending {
|
&.paused {
|
||||||
background-image: linear-gradient(to right, darken($gray-lighter, 10), $gray-lighter);
|
background-image: linear-gradient(to right, darken($gray-lighter, 20), darken($gray-lighter, 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pending, &.idle {
|
||||||
|
background-image: linear-gradient(to right, lighten($brand-info, 20), $brand-info);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.seeding {
|
&.seeding {
|
||||||
background-image: linear-gradient(to right, lighten($brand-info, 20), $brand-info);
|
background-image: linear-gradient(to right, lighten($brand-primary, 20), $brand-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.leeching {
|
&.leeching {
|
||||||
|
|
|
@ -5,14 +5,14 @@ export const FILTER_UNSUBSCRIBE = 'FILTER_UNSUBSCRIBE';
|
||||||
|
|
||||||
export function filter_subscribe(kind='torrent', criteria=[]) {
|
export function filter_subscribe(kind='torrent', criteria=[]) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
const serial = ws_send(FILTER_SUBSCRIBE, { criteria, kind });
|
const serial = ws_send(FILTER_SUBSCRIBE, { kind, criteria });
|
||||||
dispatch({ type: FILTER_SUBSCRIBE, serial });
|
dispatch({ type: FILTER_SUBSCRIBE, serial, kind, criteria });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filter_unsubscribe(serial) {
|
export function filter_unsubscribe(serial) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
ws_send(FILTER_UNSUBSCRIBE, { serial });
|
ws_send(FILTER_UNSUBSCRIBE, { filter_serial: serial });
|
||||||
dispatch({ type: FILTER_UNSUBSCRIBE, serial });
|
dispatch({ type: FILTER_UNSUBSCRIBE, serial });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,19 @@ import {
|
||||||
export default function filter_subscribe(state = [], action) {
|
export default function filter_subscribe(state = [], action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case FILTER_SUBSCRIBE: {
|
case FILTER_SUBSCRIBE: {
|
||||||
const { serial } = action;
|
const { serial, kind, criteria } = action;
|
||||||
return [...state, serial];
|
return [
|
||||||
|
...state,
|
||||||
|
{
|
||||||
|
serial,
|
||||||
|
kind,
|
||||||
|
criteria
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
case FILTER_UNSUBSCRIBE: {
|
case FILTER_UNSUBSCRIBE: {
|
||||||
const { serial } = action;
|
const { _serial } = action;
|
||||||
return state.filter(s => s !== serial);
|
return state.filter(({ serial }) => serial !== _serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
|
|
|
@ -10,12 +10,13 @@ export default function ws_send(type, body, callback = null) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
transactions[_serial] = callback;
|
transactions[_serial] = callback;
|
||||||
}
|
}
|
||||||
const msg = JSON.stringify({
|
const obj = {
|
||||||
type,
|
type,
|
||||||
serial: _serial,
|
serial: _serial,
|
||||||
...body
|
...body
|
||||||
});
|
};
|
||||||
console.log("->", msg);
|
const msg = JSON.stringify(obj);
|
||||||
|
console.log("->", obj);
|
||||||
ws.send(msg);
|
ws.send(msg);
|
||||||
return _serial;
|
return _serial;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,5 +19,6 @@ const store = createStore(
|
||||||
);
|
);
|
||||||
|
|
||||||
export const dispatch = action => store.dispatch(action);
|
export const dispatch = action => store.dispatch(action);
|
||||||
|
export const getState = () => store.getState();
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|
72
src/torrent_state.js
Normal file
72
src/torrent_state.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { filter_subscribe, filter_unsubscribe } from './actions/filter_subscribe';
|
||||||
|
import { push } from 'react-router-redux';
|
||||||
|
/* Listen pal, we're just gonna pretend this import isn't happening */
|
||||||
|
import { dispatch, getState } from './store';
|
||||||
|
|
||||||
|
export function activeTorrents() {
|
||||||
|
const { pathname } = getState().router.location;
|
||||||
|
if (pathname.indexOf("/torrents/") !== 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return pathname.slice("/torrents/".length).split(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: invoke on page load for /torrents/:id
|
||||||
|
export function updateSubscriptions(added, removed) {
|
||||||
|
if (added.length > 0) {
|
||||||
|
added.forEach(t => {
|
||||||
|
const criteria = [
|
||||||
|
{ field: "torrent_id", op: "==", value: t }
|
||||||
|
];
|
||||||
|
dispatch(filter_subscribe("peer", criteria));
|
||||||
|
dispatch(filter_subscribe("file", criteria));
|
||||||
|
dispatch(filter_subscribe("piece", criteria));
|
||||||
|
dispatch(filter_subscribe("tracker", criteria));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (removed.length > 0) {
|
||||||
|
const subscriptions = getState().filter_subscribe;
|
||||||
|
removed.forEach(t => {
|
||||||
|
const serials = subscriptions
|
||||||
|
.filter(sub => sub.criteria[0] && sub.criteria[0].value == t)
|
||||||
|
.map(sub => sub.serial);
|
||||||
|
serials.forEach(serial => dispatch(filter_unsubscribe(serial)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const selectop = {
|
||||||
|
EXCLUSIVE: 1,
|
||||||
|
UNION: 2,
|
||||||
|
SUBTRACT: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
export function selectTorrent(t, action = UNION) {
|
||||||
|
let active = activeTorrents(getState().router);
|
||||||
|
let removed = [], added = [];
|
||||||
|
switch (action) {
|
||||||
|
case selectop.EXCLUSIVE:
|
||||||
|
removed = active.slice();
|
||||||
|
active = [t.id];
|
||||||
|
added = [t.id];
|
||||||
|
break;
|
||||||
|
case selectop.UNION:
|
||||||
|
if (active.indexOf(t.id) === -1) {
|
||||||
|
active = [...active, t.id];
|
||||||
|
added = [t.id];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case selectop.SUBTRACT:
|
||||||
|
if (active.indexOf(t.id) !== -1) {
|
||||||
|
removed = [t.id];
|
||||||
|
active = active.filter(a => a != t.id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const url = active.length === 0 ? "/" : `/torrents/${active.join(',')}`;
|
||||||
|
if (url !== getState().router.location) {
|
||||||
|
dispatch(push(url));
|
||||||
|
}
|
||||||
|
updateSubscriptions(added, removed);
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
// TODO: use component lifecycle functions here to invoke
|
||||||
|
// torrent_state.updateSubscriptions
|
||||||
|
|
||||||
function torrent_details(props) {
|
function torrent_details(props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { push } from 'react-router-redux';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { activeTorrents, selectTorrent, selectop } from '../torrent_state';
|
||||||
|
|
||||||
function formatBitrate(bitrate) {
|
function formatBitrate(bitrate) {
|
||||||
if (bitrate > 1000000000) {
|
if (bitrate > 1000000000) {
|
||||||
|
@ -14,44 +14,10 @@ function formatBitrate(bitrate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function activeTorrents(router) {
|
|
||||||
const { pathname } = router.location;
|
|
||||||
if (pathname.indexOf("/torrents/") !== 0) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
return pathname.slice("/torrents/".length).split(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const EXCLUSIVE = 1, UNION = 2, SUBTRACT = 3;
|
|
||||||
|
|
||||||
function selectTorrent(dispatch, t, router, action = UNION) {
|
|
||||||
let active = activeTorrents(router);
|
|
||||||
switch (action) {
|
|
||||||
case EXCLUSIVE:
|
|
||||||
active = [t.id];
|
|
||||||
break;
|
|
||||||
case UNION:
|
|
||||||
if (active.indexOf(t.id) === -1) {
|
|
||||||
active = [...active, t.id];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SUBTRACT:
|
|
||||||
if (active.indexOf(t.id) !== -1) {
|
|
||||||
active = active.filter(a => a != t.id);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const url = active.length === 0 ? "/" : `/torrents/${active.join(',')}`;
|
|
||||||
if (url !== router.location) {
|
|
||||||
dispatch(push(url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TorrentTable extends Component {
|
class TorrentTable extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { torrents, router, dispatch } = this.props;
|
const { torrents } = this.props;
|
||||||
const active = activeTorrents(router);
|
const active = activeTorrents();
|
||||||
return (
|
return (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -81,8 +47,8 @@ class TorrentTable extends Component {
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={active.indexOf(t.id) !== -1}
|
checked={active.indexOf(t.id) !== -1}
|
||||||
onChange={e =>
|
onChange={e =>
|
||||||
selectTorrent(dispatch,
|
selectTorrent(t,
|
||||||
t, router, e.target.checked ? UNION : SUBTRACT)}
|
e.target.checked ? selectop.UNION : selectop.SUBTRACT)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -90,7 +56,7 @@ class TorrentTable extends Component {
|
||||||
href="#"
|
href="#"
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
selectTorrent(dispatch, t, router, EXCLUSIVE);
|
selectTorrent(t, selectop.EXCLUSIVE);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t.name}
|
{t.name}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user