import React, { Component } from 'react';
import DVideo from '../abis/DVideo.json'
import Navbar from './Navbar'
import Main from './Main'
import Web3 from 'web3';
import './App.css';
//Declare IPFS
const ipfsClient = require('ipfs-http-client')
const ipfs = ipfsClient({ host: 'ipfs.infura.io', port: 5001, protocol: 'https' }) // leaving out the arguments will default to these values
class App extends Component {
async componentWillMount() {
await this.loadWeb3()
await this.loadBlockchainData()
}
async loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum)
await window.ethereum.enable()
}
else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider)
}
else {
window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
}
}
async loadBlockchainData() {
const web3 = window.web3
// Load account
const accounts = await web3.eth.getAccounts()
console.log(accounts[0])
this.setState({ account: accounts[0] })
// Network ID
const networkId = await web3.eth.net.getId()
const networkData = DVideo.networks[networkId]
if (networkData) {
const dvideo = new web3.eth.Contract(DVideo.abi, networkData.address)
this.setState({ dvideo })
const videosCount = await dvideo.methods.videoCount().call()
this.setState({ videosCount })
// Load videos, sort by newest
for (var i = videosCount; i >= 1; i--) {
const video = await dvideo.methods.videos(i).call()
this.setState({
videos: [...this.state.videos, video]
})
}
//Set latest video with title to view as default
const latest = await dvideo.methods.videos(videosCount).call()
this.setState({
currentHash: latest.hash,
currentTitle: latest.title
})
this.setState({ loading: false })
} else {
window.alert('DVideo contract not deployed to detected network.')
}
}
//Get video
captureFile = event => {
event.preventDefault()
const file = event.target.files[0]
const reader = new window.FileReader()
reader.readAsArrayBuffer(file)
reader.onloadend = () => {
this.setState({ buffer: Buffer(reader.result) })
console.log('buffer', this.state.buffer)
}
}
//Upload video
uploadVideo = title => {
console.log("Submitting file to IPFS...")
//adding file to the IPFS
ipfs.add(this.state.buffer, (error, result) => {
console.log('IPFS result', result)
if (error) {
console.error(error)
return
}
this.setState({ loading: true })
this.state.dvideo.methods.uploadVideo(result[0].hash, title).send({ from: this.state.account }).on('transactionHash', (hash) => {
this.setState({ loading: false })
})
})
}
//Change Video
changeVideo = (hash, title) => {
this.setState({ 'currentHash': hash });
this.setState({ 'currentTitle': title });
}
constructor(props) {
super(props)
this.state = {
buffer: null,
account: '',
dvideo: null,
videos: [],
loading: true,
currentHash: null,
currentTitle: null
}
//Bind functions
this.uploadVideo = this.uploadVideo.bind(this)
this.captureFile = this.captureFile.bind(this)
this.changeVideo = this.changeVideo.bind(this)
}
render() {
return (
<div>
<Navbar
account={this.state.account}
/>
{this.state.loading
? <div id="loader" className="text-center mt-5"><p>Loading...</p></div>
: <Main
captureFile={this.captureFile}
uploadVideo={this.uploadVideo}
currentHash={this.state.currentHash}
currentTitle={this.state.currentTitle}
videos={this.state.videos}
changeVideo={this.changeVideo}
/>
}
</div>
);
}
}
export default App;
--------------------------------
//src/components/main.js
import React, { Component } from 'react';
class Main extends Component {
render() {
return (
<div className="container-fluid text-monospace">
<br></br>
<br></br>
<div className="row">
<div className="col-md-10">
<div className="embed-responsive embed-responsive-16by9" style={{ maxHeight: '768px' }}>
{/* Video... */}
<video
src={`https://ipfs.infura.io/ipfs/${this.props.currentHash}`}
controls
>
</video>
</div>
<h3><b><i>{this.props.currentTitle}</i></b></h3>
</div>
<div className="col-md-2 overflow-auto text-center" style={{ maxHeight: '768px', minWidth: '175px' }}>
<h5><b>Share Video</b></h5>
<form onSubmit={(event) => {
{/* Upload Video...*/ }
event.preventDefault()
const title = this.videoTitle.value
this.props.uploadVideo(title)
}} >
{/* Get Video...*/}
<input type='file' accept=".mp4, .mkv .ogg .wmv" onChange={this.props.captureFile} style={{ width: '250px' }} />
<div className="form-group mr-sm-2">
<input
id="videoTitle"
type="text"
ref={(input) => { this.videoTitle = input }}
className="form-control-sm"
placeholder="Title..."
required />
</div>
<button type="submit" className="btn btn-danger btn-block btn-sm">Upload!</button>
</form>
{/* Map Video...*/}
{/* Return Video...*/}
{this.props.videos.map((video, key) => {
return (
<div className="card mb-4 text-center bg-secondary mx-auto" style={{ width: '175px' }} key={key} >
<div className="card-title bg-dark">
<small className="text-white"><b>{video.title}</b></small>
</div>
<div>
<p onClick={() => this.props.changeVideo(video.hash, video.title)}>
<video
src={`https://ipfs.infura.io/ipfs/${video.hash}`}
style={{ width: '150px' }}
/>
</p>
</div>
</div>
)
})}
</div>
</div>
</div>
);
}
}
export default Main;
---------------------------
//src/contracts/DVideo.sol
pragma solidity ^0.5.0;
contract DVideo {
uint public videoCount = 0;
string public name = "DVideo";
mapping(uint => Video) public videos;
//Create id=>struct mapping
//Create Struct
struct Video{
uint id;
string hash;
string title;
address author;
}
//Create Event
event VideoUploaded(
uint id,
string hash,
string title,
address author
);
constructor() public {
}
function uploadVideo(string memory _videoHash, string memory _title) public {
// Make sure the video hash exists
require(bytes(_videoHash).length > 0);
// Make sure video title exists
require(bytes(_title).length > 0);
// Make sure uploader address exists
require(msg.sender != address(0));
// Increment video id
videoCount++;
// Add video to the contract
videos[videoCount] = Video(videoCount, _videoHash, _title, msg.sender);
// Trigger an event
emit VideoUploaded(videoCount, _videoHash, _title, msg.sender);
}
}
-------------------------
//test/test.js
const DVideo = artifacts.require('./DVideo.sol')
require('chai')
.use(require('chai-as-promised'))
.should()
contract('DVideo', ([deployer, author]) => {
let dvideo
before(async () => {
dvideo = await DVideo.deployed()
})
describe('deployment', async () => {
it('deploys successfully', async () => {
const address = await dvideo.address
assert.notEqual(address, 0x0)
assert.notEqual(address, '')
assert.notEqual(address, null)
assert.notEqual(address, undefined)
})
it('has a name', async () => {
const name = await dvideo.name()
assert.equal(name, 'DVideo')
})
})
describe('videos', async () => {
let result, videoCount
const hash = 'QmV8cfu6n4NT5xRr2AHdKxFMTZEJrA44qgrBCr739BN9Wb'
before(async () => {
result = await dvideo.uploadVideo(hash, 'Video title', { from: author })
videoCount = await dvideo.videoCount()
})
//check event
it('creates videos', async () => {
// SUCESS
assert.equal(videoCount, 1)
const event = result.logs[0].args
assert.equal(event.id.toNumber(), videoCount.toNumber(), 'id is correct')
assert.equal(event.hash, hash, 'Hash is correct')
assert.equal(event.title, 'Video title', 'title is correct')
assert.equal(event.author, author, 'author is correct')
// FAILURE: Video must have hash
await dvideo.uploadVideo('', 'Video title', { from: author }).should.be.rejected;
// FAILURE: Video must have title
await dvideo.uploadVideo('Video hash', '', { from: author }).should.be.rejected;
})
//check from Struct
it('lists videos', async () => {
const video = await dvideo.videos(videoCount)
assert.equal(video.id.toNumber(), videoCount.toNumber(), 'id is correct')
assert.equal(video.hash, hash, 'Hash is correct')
assert.equal(video.title, 'Video title', 'title is correct')
assert.equal(video.author, author, 'author is correct')
})
})
})
reference:
No comments:
Post a Comment